Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ably Php Laravel Package

ably/ably-php

Official Ably Pub/Sub PHP SDK for realtime messaging, message history, presence, and push notifications. Install via Composer, then publish and subscribe using REST or realtime clients. Includes Laravel integration options.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pick the right entry point first. This package is the raw PHP REST SDK; if you are in a Laravel app, read the first table before you write any code.

Need Use
Publish/history/presence queries from your backend (jobs, listeners, controllers) ably/ably-php (this package)
Facade + DI + config file for the above ably/ably-php-laravel
Broadcast Laravel events to a JS frontend via Echo ably/laravel-broadcaster
Realtime subscribe from PHP Not supported here — use the MQTT adapter or subscribe client-side (JS/iOS/Android)
composer require ably/ably-php

Minimal first request (REST is stateless — each call is just an HTTPS request):

use Ably\AblyRest;

$ably = new AblyRest(config('services.ably.key'));
$channel = $ably->channel('test-channel');
$channel->publish('test-event', ['hello' => 'world']);

Where to look first

  1. README.md — install + the ten-line publish example above.
  2. https://ably.com/docs/getting-started/php and https://ably.com/docs/rest — the REST surface this SDK implements.
  3. src/AblyRest.php, src/Channel.php, src/Models/ — the actual API you will call; this is more accurate than the docs for odd cases.
  4. CHANGELOG.md — you must be on ≥ 1.1.9 (protocol v1 deprecation from Nov 2025); prefer the latest 1.1.12+ for PHP 8.4/8.5 fixes.

First real use case for a Laravel dev: server-side publish from a domain event, with the browser subscribing via the JS SDK.

// app/Events/OrderShipped.php (broadcast side stays on the Laravel broadcaster)
// app/Listeners/PublishToAbly.php
public function handle(OrderShipped $event): void
{
    app(AblyRest::class)
        ->channel("orders:{$event->order->id}")
        ->publish('shipped', ['tracking' => $event->tracking, 'at' => now()->toIso8601String()]);
}

Implementation Patterns

1. Bind a singleton in the container, configured from config/services.php. The client is stateless but re-instantiating it per call wastes option parsing and makes swapping for a fake harder.

// AppServiceProvider::register()
$this->app->singleton(AblyRest::class, fn () => new AblyRest([
    'key'      => config('services.ably.key'),
    'clientId' => config('services.ably.client_id', 'server'),
    'timeout'  => 10,
    'logLevel' => app()->isLocal() ? 3 : 1,
]));

2. Wrap the SDK behind your own thin interface. Ably ships no fake() or mock client, so unit tests need your own seam:

interface Broadcaster { public function publish(string $channel, string $event, mixed $data): void; }

class AblyBroadcaster implements Broadcaster { /* delegates to AblyRest */ }

Then bind a NullBroadcaster or a recording fake in tests. Integration tests hit a dedicated Ably sandbox app, never production.

3. Publish from queue jobs, not from the request cycle. Publishing is synchronous cURL; a slow Ably call must not add latency to a checkout. Combine with ShouldQueue listeners and an explicit timeout.

class PublishMessage implements ShouldQueue
{
    public $tries = 3;
    public $backoff = [1, 5, 15];

    public function handle(AblyRest $ably): void { /* publish */ }
}

4. Token authentication for the browser (do not ship your API key to JS). Generate a TokenRequest server-side and let the frontend JS SDK request a token:

$tokenRequest = $ably->auth->createTokenRequest([
    'clientId' => $user->id,
    'capability' => json_encode([
        "orders:{$order->id}"     => ['subscribe'],
        "user:{$user->id}:inbox"  => ['subscribe', 'publish'],
    ]),
    'ttl' => 3_600_000,
]);

return response()->json($tokenRequest->toArray()); // consumed by Ably.Realtime({ authUrl: '/api/ably-token' })

Issue the narrowest capability you can; capabilities are per-namespace, so use channel namespaces (private:user:{id}, orders:{id}) and never grant ['*'] to a browser client.

5. History and pagination. Use history() for backfill when a client reconnects. PaginatedResult exposes hasNext() and isLast() as attributes since v1.0:

$page = $channel->history(['limit' => 100, 'direction' => 'backwards', 'start' => $sinceMs]);
do {
    foreach ($page->items as $message) { /* store/serve */ }
    if ($page->hasNext ?? $page->hasNext()) { $page = $page->next(); }
} while (! $page->isLast);

Timestamps are milliseconds, not seconds — a classic Laravel Carbon conversion bug (now()->valueOf()).

6. Presence queries for presence-as-a-service dashboards. REST gives you presence->get() / presence->history(), which is enough for "who is online in this room" pages. It does not give you subscriptions — for live presence you need a client-side SDK or MQTT.

7. Batch publish for fan-out. One HTTP call to many channels instead of N calls:

$batch = $ably->batch; // see src/Http for BatchRequest

Batch publish had a historical bug (sent as JSON rather than msgpack, fixed in 1.1.11). Keep the batch small and validate per-message payloads.

8. Integrate with the Laravel broadcaster when the frontend is Vue/React. If your only backend need is "broadcast an event," you may not need this package directly — install ably/laravel-broadcaster and let Laravel's Broadcast::channel() capability map to Ably channels. Reach for ably-php directly when you need history, presence, token generation, or push-admin calls from the backend.

9. Idempotency for retries. When a queue job retries a publish, duplicate messages can land in the channel. Use Ably's idempotent publishing (or a dedupe key derived from your job id) so consumers can safely ignore replays.

Gotchas and Tips

REST-only — the biggest trap. There is no channel->subscribe() in PHP. If a requirement says "Laravel worker listens for Ably messages," the answer is not this SDK: use the MQTT adapter + Mosquitto PHP, or push subscriptions into a JS/mobile client. Don't try to build polling loops on history() as a substitute; it will burn rate limits.

Version floor matters. Releases before 1.1.9 are deprecated against protocol v1 (Nov 1, 2025). Pin ^1.1.12 at minimum — 1.1.11 fixed PHP 8.4 implicit-nullable deprecations and the batch-publish encoding bug, 1.1.12 removed the curl_close() deprecation noise on PHP 8.5. Test on the PHP version your prod image actually runs.

clientId and token auth interact non-obviously. If a token's clientId is set, publishing a message with a different per-message clientId is rejected by the server (RSL1m4). Either omit clientId in AblyRest options for pure server publishing, or use one consistent identity. Historically the library forced token auth whenever clientId was set (fixed in 1.1.5) — if you're on an older version, this is why your "basic auth + clientId" setup misbehaves.

Config and host fallback quirks.

  • fallbackHosts is used automatically on 5xx/network failures; if you set a custom host, define fallbackHosts explicitly or you may fail over somewhere you don't expect.
  • https_proxy env var is honoured (since 1.1.1) — good for corporate egress, but it can silently route traffic through a proxy in CI.
  • A self-signed CA in your chain historically triggered cURL error 60 (fixed around 0.9) — still a common symptom when a middleware proxy terminates TLS; check the trust bundle, not the SDK.
  • Timezone mismatches (Mac mismatch) were a real past issue on timestamps — always emit and consume epoch milliseconds, never local-time strings.

Error handling. Failures throw Ably\Exceptions\AblyException with a statusCode and Ably code. Distinguish:

  • 40100/40101/40102 — auth/capability problems (a capability string typo looks like this).
  • 429xx — rate limited; retry with backoff in the queue job.
  • 5xx — let fallback hosts try, then retry the job.

Never swallow these in a listener; log $e->getCode() and $e->getMessage() because the message contains the Ably error detail.

Payload and encoding. Messages are capped around 64 KiB. If you're sending large models, publish an ID and let the client fetch, or enable the SDK's msgpack support. Encrypted channels (CipherParams) require the frontend to use the exact same base64 key — mismatched keys surface as silent decode failures in the browser, not as server errors.

Debugging. Set logLevel in the client options (0 = none, 3 = verbose) rather than sprinkling dd(). For a raw view of what's on the wire, call the low-level $ably->request('GET', '/channels') — useful for verifying X-Ably-Lib/Ably-Agent headers and confirming your key is being read at all. The Ably-Agent header (RSC7d, added 1.1.6) identifies the SDK version to Ably support; include it when filing issues.

Pagination is attribute-based. $result->hasNext and $result->isLast are properties in v1.0+, not methods. Code written against pre-1.0 examples will fatal.

Extension points. AblyRest accepts a host/environment for sandbox and custom endpoints (useful for a local stub server in integration tests), a custom transport isn't exposed, but request() is public and is the cleanest place to intercept for logging. Prefer building your own repository/interface on top rather than subclassing AblyRest — internals change between minor versions and the package has a small maintainer surface (61 stars, single-vendor stewardship), so keep upgrades cheap.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package