Migrate from Pusher to Vask (Rails). Drop-in for pusher-http-ruby.
Vask speaks the Pusher protocol, so a Rails app using pusher-http-ruby and pusher-js usually migrates by changing credentials, host, and cached assets.
Migration summary
At a glance
- Type
- Drop-in host swap
- Typical time
- 10-15 minutes
- Server SDK
- pusher-http-ruby unchanged
- Client SDK
- pusher-js unchanged
- Auth changes
- reuse /pusher/auth; keep Rails CSRF header
- Rollback
- restore Pusher credentials and rebuild cached assets
Files touched
- config/initializers/pusher.rb
- Rails credentials or ENV
- app/javascript/pusher.js
- app/controllers/pusher_controller.rb
Get started
Realtime made simple.
Free Tier: 500K broadcasts/mo and 100 concurrent across unlimited apps. $10/mo when you outgrow it.
Minimal config diff
Set the Vask app key as both PUSHER_APP_ID and PUSHER_APP_KEY. If your SDK asks for an app id, use the Vask app key. Vask does not issue a separate customer-facing app id.
- PUSHER_APP_ID=123456
- PUSHER_APP_KEY=abc123
- PUSHER_APP_SECRET=xyz789
- PUSHER_APP_CLUSTER=us2
+ PUSHER_APP_ID=your_vask_key
+ PUSHER_APP_KEY=your_vask_key
+ PUSHER_APP_SECRET=your_vask_secret
+ PUSHER_HOST=wss.vask.dev
+ PUSHER_PORT=443
+ PUSHER_SCHEME=https
+ PUSHER_APP_CLUSTER=mt1Then make sure the Rails initializer uses the explicit host:
require 'pusher'
Pusher.app_id = ENV['PUSHER_APP_ID']
Pusher.key = ENV['PUSHER_APP_KEY']
Pusher.secret = ENV['PUSHER_APP_SECRET']
Pusher.host = ENV.fetch('PUSHER_HOST', 'wss.vask.dev')
Pusher.port = ENV.fetch('PUSHER_PORT', 443).to_i
Pusher.scheme = ENV.fetch('PUSHER_SCHEME', 'https')
Pusher.cluster = ENV.fetch('PUSHER_APP_CLUSTER', 'mt1')
Pusher.encrypted = trueRollback
Put the old Pusher values back in credentials or ENV, remove or override PUSHER_HOST, clear asset caches with your normal Rails workflow, and redeploy. Because the gem and client SDK stay the same, rollback is another credential swap.
What changes / what stays
- Changes: host, key, secret, optional compatibility cluster, and any compiled JavaScript that embeds those values.
- Stays:
Pusher.trigger, channel names, event names,pusher-js, private/presence auth signatures, and any ActionCable adapter that reads the same Pusher config.
Server publish
Keep your existing publish calls:
Pusher.trigger('orders', 'order.created', { id: order.id })If you publish through an ActionCable Pusher adapter, update the adapter credentials instead of adding a second publisher. If you use ActionCable with the default Redis adapter and no Pusher-compatible SDK, this guide is not a required migration; that stack can keep running as-is.
Client subscribe
Wherever Rails loads pusher-js (importmap, jsbundling-rails, Sprockets, or CDN), point the browser at Vask:
import Pusher from 'pusher-js';
const pusher = new Pusher(window.VASK_PUSHER.key, {
cluster: window.VASK_PUSHER.cluster || 'mt1',
wsHost: window.VASK_PUSHER.host || 'wss.vask.dev',
wsPort: 443,
wssPort: 443,
forceTLS: true,
enabledTransports: ['ws', 'wss'],
authEndpoint: '/pusher/auth',
auth: {
headers: {
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]')
?.content,
},
},
});Do not assume process.env exists in the browser unless your Rails bundler replaces it. Template the public key and host into the page or expose them through your bundler's public-env pattern.
Private and presence channels
The auth route stays the same:
post '/pusher/auth', to: 'pusher#auth'class PusherController < ApplicationController
def auth
return head :forbidden unless current_user
render json: Pusher.authenticate(
params[:channel_name],
params[:socket_id],
user_id: current_user.id.to_s,
user_info: { name: current_user.name }
)
end
endRails 403s usually mean the CSRF header is missing, the session did not populate current_user, or the secret still contains the old Pusher value.
Verify
- Deploy or restart Rails with the new credentials.
- Hard refresh the browser and confirm a WebSocket connects to
wss.vask.dev. - Trigger a
Pusher.triggercall from a controller, job, orbin/rails console. - Subscribe to one public channel and one private or presence channel before cutting production traffic.
Gotchas
- Asset cache still has the old host. Clear
tmp/cache, expire CDN assets if needed, and run your normal asset pipeline so the browser receives the newwsHost. - Cluster expectations. Vask routes by
PUSHER_HOST, not cluster. Keepmt1only for SDK compatibility. - ActionCable paths can coexist. Leaving
mount ActionCable.server => '/cable'in place is fine while pusher-js connects to Vask. Remove it later only if no clients use it.
Where to go next
- Run the Pusher fan-out calculator against your workload.
- Read the Pusher vs Vask comparison for pricing and protocol detail.
- Check the Rails guide for advanced setup.
- If a Laravel service shares the same events, use the Laravel migration guide.
- Does pusher-http-ruby work unchanged?
- Yes. Keep the gem and your existing trigger calls. Set the host to wss.vask.dev, use your Vask app key and secret. If your SDK asks for an app id, use the Vask app key.
- What happens to private and presence auth?
- Keep the same /pusher/auth route and Pusher.authenticate call. The Rails-specific check is the CSRF header from pusher-js; if private channels return 403, confirm X-CSRF-Token, current_user, and the Vask secret.
- Do I need to replace ActionCable?
- No. ActionCable on Redis can stay if it serves the app. This guide is for Rails apps already using pusher-http-ruby directly, or an ActionCable adapter that forwards through Pusher-compatible credentials.
- How do I roll back if browsers still connect to Pusher or fail to connect?
- Restore the old Pusher credentials, clear Rails asset caches, rebuild with your normal asset pipeline, and redeploy. The code path is symmetric because the migration is a host and credential swap.
Get going
Vask keeps the Rails migration at the credential layer: same gem, same client, same auth route, new host.
Make the switch
Drop in your Vask credentials. Keep your gem.
pusher-http-ruby on the server, pusher-js on the client, the same auth callback at /pusher/auth. Most teams ship the cutover in around fifteen minutes.