Migration from Pusher

Soketify is 100% Pusher-compatible. Migrating from Pusher takes minutes, not days. You change your host configuration and everything else stays exactly the same.

What Changes

The only change required is pointing your Pusher SDKs to Soketify servers instead of Pusher servers. Specifically:

SettingPusherSoketify
WebSocket hostws-<Cluster>.pusher.comws.soketify.com
REST API hostapi-<Cluster>.pusher.comapi.soketify.com
App credentialsFrom Pusher dashboardFrom Soketify dashboard
ClusterRegion-specific (e.g., mt1, us2, eu)Any value (e.g., "default")

One exception: the two Java SDKs

In most SDKs the cluster is a dead string once you set a host, so you can leave it alone. The two Java libraries are the exception, because there setCluster() is not a hint but an assignment that overwrites the host: the Android client (com.pusher:pusher-java-client) rewrites it to ws-<cluster>.pusher.com, and the server library (pusher-http-java) rewrites it to api-<cluster>.pusher.com. In both, keeping your old setCluster line next to a new setHost line means whichever you happen to call last decides where the traffic goes. Delete the setCluster call rather than keeping it. The Android section below shows exactly what to change.

What Stays the Same

Everything else in your application remains unchanged:

  • SDK libraries You keep using pusher-js, pusher (Node.js), pusher-http-php, pusher-http-ruby, etc.
  • Channel subscriptions Your channel names, events, and bindings work as-is.
  • Auth endpoints Your existing private/presence channel authentication code stays the same (just update the Pusher instance config on your server).
  • Event structure Event names, payloads, and triggering logic are identical.
  • REST API The same endpoints, parameters, and response formats.
  • Client events Client-to-client messaging on private/presence channels works identically.
  • Webhooks Channel occupied/vacated and presence member webhooks use the same format.

Zero Code Changes

Your application logic does not need to change. No event names, no channel names, no SDK version changes. Soketify implements the full Pusher protocol.

Client-Side Migration (JavaScript)

Before (Pusher)

Before - Pusher
javascript
import Pusher from "pusher-js";

const pusher = new Pusher("YOUR_PUSHER_KEY", {
  cluster: "us2",
});

After (Soketify)

After - Soketify
javascript
import Pusher from "pusher-js";

const pusher = new Pusher("YOUR_SOKETIFY_KEY", {
  wsHost: "ws.soketify.com",
  wsPort: 443,
  wssPort: 443,
  forceTLS: true,
  disableStats: true,
  enabledTransports: ["ws", "wss"],
  cluster: "default",
});

The rest of your client code (subscriptions, event bindings, callbacks) remains identical. No changes needed.

Client-Side Migration (Android / Kotlin)

The official Android client is com.pusher:pusher-java-client. Read the two callouts under the code before you edit anything: this is the SDK where the obvious edit silently sends your traffic to Pusher instead of to us.

Before (Pusher)

Before - Pusher
kotlin
import com.pusher.client.Pusher
import com.pusher.client.PusherOptions

val options = PusherOptions()
    .setCluster("us2")

val pusher = Pusher("YOUR_PUSHER_KEY", options)
pusher.connect()

After (Soketify)

After - Soketify
kotlin
import com.pusher.client.Pusher
import com.pusher.client.PusherOptions

// No setCluster() here: it would overwrite the host with ws-<cluster>.pusher.com.
val options = PusherOptions()
    .setHost("ws.soketify.com")
    .setWsPort(443)
    .setWssPort(443)
    .setUseTLS(true)

val pusher = Pusher("YOUR_SOKETIFY_KEY", options)
pusher.connect()

Remove setCluster(), do not keep it

setCluster("us2") is not a routing hint in this SDK. It assigns host = ws-us2.pusher.com, wsPort = 80 and wssPort = 443, all three at once, so it overwrites the host you configured. The natural edit here is to keep the existing setCluster line and add setHost after it, and whether that works depends purely on which of the two you happen to call last. If setCluster runs last, your app opens a connection to Pusher's real servers carrying your Soketify key, and the failure looks like an invalid-key error rather than a wrong-host one. Delete the setCluster call. Unlike pusher-js, this client has no cluster option to satisfy.

Set the port with setWssPort, not setWsPort

The client builds its URL as wss://<host>:<wssPort> when TLS is on and ws://<host>:<wsPort> when it is off, so setUseTLS(true) does not carry over a port you set with setWsPort: that value is simply ignored and you get 443. On ws.soketify.com this is invisible because 443 is what you wanted anyway, but if you ever point the client at a non-standard port (a staging box, a local container) only setWssPort will take effect. Setting both, as below, is correct in either case.

Server-Side Migration (Node.js)

Before (Pusher)

Before - Pusher
javascript
const Pusher = require("pusher");

const pusher = new Pusher({
  appId: "YOUR_PUSHER_APP_ID",
  key: "YOUR_PUSHER_KEY",
  secret: "YOUR_PUSHER_SECRET",
  cluster: "us2",
  useTLS: true,
});

After (Soketify)

After - Soketify
javascript
const Pusher = require("pusher");

const pusher = new Pusher({
  appId: "YOUR_SOKETIFY_APP_ID",
  key: "YOUR_SOKETIFY_KEY",
  secret: "YOUR_SOKETIFY_SECRET",
  host: "api.soketify.com",
  port: "443",
  useTLS: true,
  cluster: "default",
});

Server-Side Migration (PHP)

Before (Pusher)

Before - Pusher
php
use Pusher\Pusher;

$pusher = new Pusher(
    'YOUR_PUSHER_KEY',
    'YOUR_PUSHER_SECRET',
    'YOUR_PUSHER_APP_ID',
    [
        'cluster' => 'us2',
        'useTLS' => true,
    ]
);

After (Soketify)

After - Soketify
php
use Pusher\Pusher;

$pusher = new Pusher(
    'YOUR_SOKETIFY_KEY',
    'YOUR_SOKETIFY_SECRET',
    'YOUR_SOKETIFY_APP_ID',
    [
        'host' => 'api.soketify.com',
        'port' => 443,
        'scheme' => 'https',
        'useTLS' => true,
        'cluster' => 'default',
    ]
);

Server-Side Migration (Ruby)

Before (Pusher)

Before - Pusher
ruby
require 'pusher'

pusher = Pusher::Client.new(
  app_id: 'YOUR_PUSHER_APP_ID',
  key: 'YOUR_PUSHER_KEY',
  secret: 'YOUR_PUSHER_SECRET',
  cluster: 'us2',
  use_tls: true
)

After (Soketify)

After - Soketify
ruby
require 'pusher'

pusher = Pusher::Client.new(
  app_id: 'YOUR_SOKETIFY_APP_ID',
  key: 'YOUR_SOKETIFY_KEY',
  secret: 'YOUR_SOKETIFY_SECRET',
  host: 'api.soketify.com',
  port: 443,
  use_tls: true,
  cluster: 'default'
)

Server-Side Migration (Python)

Before (Pusher)

Before - Pusher
python
import pusher

pusher_client = pusher.Pusher(
    app_id='YOUR_PUSHER_APP_ID',
    key='YOUR_PUSHER_KEY',
    secret='YOUR_PUSHER_SECRET',
    cluster='us2',
    ssl=True
)

After (Soketify)

After - Soketify
python
import pusher

pusher_client = pusher.Pusher(
    app_id='YOUR_SOKETIFY_APP_ID',
    key='YOUR_SOKETIFY_KEY',
    secret='YOUR_SOKETIFY_SECRET',
    host='api.soketify.com',
    port=443,
    ssl=True,
    cluster='default'
)

Server-Side Migration (.NET / C#)

The official .NET server library is the PusherServer NuGet package.

Before (Pusher)

Before - Pusher
csharp
using PusherServer;

var options = new PusherOptions
{
    Cluster = "us2",
    Encrypted = true,
};

var pusher = new Pusher(
    "YOUR_PUSHER_APP_ID",
    "YOUR_PUSHER_KEY",
    "YOUR_PUSHER_SECRET",
    options);

After (Soketify)

After - Soketify
csharp
using PusherServer;

var options = new PusherOptions
{
    // HostName, not Host. Bare hostname: no port, no scheme.
    HostName = "api.soketify.com",
    Encrypted = true,
};

var pusher = new Pusher(
    "YOUR_SOKETIFY_APP_ID",
    "YOUR_SOKETIFY_KEY",
    "YOUR_SOKETIFY_SECRET",
    options);

The option is HostName, and it takes the host on its own

Two details cost people an afternoon here. First, the property is HostName; there is no Host property on PusherOptions, so a Host = "api.soketify.com" line does not compile. Second, HostName must be the bare hostname with no port and no scheme: the library builds the URL as <scheme>://<HostName>:<Port>, so writing "api.soketify.com:443" throws UriFormatException ("Invalid port specified") as soon as Encrypted is true, and "https://api.soketify.com" throws FormatException. The port belongs in the separate Port property, and you can leave it out entirely on 443 because the library omits the scheme's default port. Encrypted = true is what selects https; without it the SDK sends your app secret over plain http. Cluster does not override HostName in this SDK, so an old Cluster line is harmless, but you may as well delete it.

Laravel Echo Migration

If you use Laravel Echo with Pusher, the migration is straightforward. Update your Echo configuration and your Laravel broadcasting config.

Echo Client Configuration

resources/js/bootstrap.js
javascript
1import Echo from "laravel-echo";
2import Pusher from "pusher-js";
3
4window.Pusher = Pusher;
5
6window.Echo = new Echo({
7  broadcaster: "pusher",
8  key: import.meta.env.VITE_SOKETIFY_APP_KEY,
9  wsHost: "ws.soketify.com",
10  wsPort: 443,
11  wssPort: 443,
12  forceTLS: true,
13  disableStats: true,
14  enabledTransports: ["ws", "wss"],
15  cluster: "default",
16});

Laravel Broadcasting Config

config/broadcasting.php
php
1// config/broadcasting.php
2'connections' => [
3    'pusher' => [
4        'driver' => 'pusher',
5        'key' => env('SOKETIFY_APP_KEY'),
6        'secret' => env('SOKETIFY_APP_SECRET'),
7        'app_id' => env('SOKETIFY_APP_ID'),
8        'options' => [
9            'host' => 'api.soketify.com',
10            'port' => 443,
11            'scheme' => 'https',
12            'useTLS' => true,
13            'cluster' => 'default',
14        ],
15    ],
16],

Environment Variables

.env
bash
BROADCAST_DRIVER=pusher
SOKETIFY_APP_ID=your-app-id
SOKETIFY_APP_KEY=your-app-key
SOKETIFY_APP_SECRET=your-app-secret

VITE_SOKETIFY_APP_KEY=${SOKETIFY_APP_KEY}

Laravel Broadcasting Channels

Your existing channel definitions in routes/channels.php and event broadcasting classes remain unchanged. Soketify works as a drop-in replacement for the Pusher driver.

Testing the Migration

After updating your configuration, verify the migration with these steps:

  1. Check the connection Open your browser console and verify the WebSocket connects successfully. You should see the connection state change to "connected".
  2. Subscribe to a channel Subscribe to a public channel and verify the pusher:subscription_succeeded event fires.
  3. Trigger a test event Use your server to trigger an event and confirm it arrives on the client.
  4. Test private channels If you use private or presence channels, verify that your auth endpoint works and subscriptions succeed.
  5. Monitor the dashboard Check the Soketify Dashboard for active connections, channels, and message counts.
migration-test.js
javascript
1// Quick connection test
2const pusher = new Pusher("YOUR_SOKETIFY_KEY", {
3  wsHost: "ws.soketify.com",
4  wsPort: 443,
5  wssPort: 443,
6  forceTLS: true,
7  disableStats: true,
8  enabledTransports: ["ws", "wss"],
9  cluster: "default",
10});
11
12pusher.connection.bind("connected", () => {
13  console.log("Connected to Soketify!");
14  console.log("Socket ID:", pusher.connection.socket_id);
15});
16
17pusher.connection.bind("error", (err) => {
18  console.error("Connection error:", err);
19});
20
21const channel = pusher.subscribe("test-migration");
22channel.bind("pusher:subscription_succeeded", () => {
23  console.log("Channel subscription works!");
24});

Rollback Strategy

Since the migration only involves configuration changes, rolling back is equally simple:

  1. Use environment variables Store all Soketify/Pusher configuration in environment variables rather than hardcoding. This makes switching between providers a matter of changing environment values.
  2. Keep your Pusher credentials Do not delete your Pusher app until you are confident the migration is successful.
  3. Staged rollout Consider migrating one environment at a time (staging first, then production) to minimize risk.
  4. To roll back Simply revert your environment variables to point back to Pusher hosts and redeploy. No code changes are needed.
.env
bash
# Easy switching via environment variables

# For Soketify
WS_HOST=ws.soketify.com
API_HOST=api.soketify.com
APP_KEY=your-soketify-key
APP_SECRET=your-soketify-secret
APP_ID=your-soketify-app-id

# To roll back to Pusher, just change these:
# WS_HOST=ws-us2.pusher.com
# API_HOST=api-us2.pusher.com
# APP_KEY=your-pusher-key
# APP_SECRET=your-pusher-secret
# APP_ID=your-pusher-app-id

Feature Flag Approach

For zero-downtime migration, you can use a feature flag or environment variable to control which WebSocket provider is used. This lets you switch instantly without redeploying.

Next Steps