Skip to content

supabase-community/realtime-ex

Supabase Realtime

Hex.pm Docs

Elixir client for Supabase Realtime. Provides OTP-powered connectivity for real-time database changes, broadcast messages, and presence features.

Features

  • OTP Supervision: Resilient connections with automatic recovery
  • Channel Subscriptions: Patterns inspired by Phoenix Channels
  • Automatic Reconnection: Exponential backoff reconnection strategy
  • Send and Push Buffers: Messages buffered while disconnected, flushed on reconnect
  • HTTP Fallback: Broadcast messages sent over HTTP when WebSocket is down
  • Token Refresh: Dynamic token resolution with access_token_fn
  • Broadcast Acknowledgment: Optional delivery confirmation for broadcasts
  • Broadcast Self: Option to receive your own broadcast messages
  • Wildcard Events: Subscribe to all events with event: "*" or event: :all
  • Presence Tracking: Track and sync user presence across clients
  • Postgres Type Transforms: Automatic conversion of database values to Elixir types

Installation

Add supabase_realtime to your list of dependencies in mix.exs:

def deps do
  [
    {:supabase_potion, "~> 0.7"},
    {:supabase_realtime, "~> 0.4.0"} # x-release-please-version
  ]
end

Quick Start

Create a Client

{:ok, client} = Supabase.init_client(
  "https://your-project.supabase.co",
  "your-api-key"
)

Define a Realtime Module

defmodule MyApp.Realtime do
  use Supabase.Realtime

  def start_link(opts \\ []) do
    Supabase.Realtime.start_link(__MODULE__, opts)
  end

  @impl true
  def handle_event({:postgres_changes, :insert, payload}) do
    IO.inspect(payload, label: "New record")
    :ok
  end

  @impl true
  def handle_event({:postgres_changes, _op, payload}) do
    IO.inspect(payload, label: "DB change")
    :ok
  end

  @impl true
  def handle_event({:broadcast, event, payload}) do
    IO.inspect({event, payload}, label: "Broadcast")
    :ok
  end

  @impl true
  def handle_event({:presence, event, payload}) do
    IO.inspect({event, payload}, label: "Presence")
    :ok
  end
end

Add to Your Supervision Tree

def start(_type, _args) do
  {:ok, client} = Supabase.init_client(
    System.fetch_env!("SUPABASE_URL"),
    System.fetch_env!("SUPABASE_KEY")
  )

  children = [
    {MyApp.Realtime, client: client}
  ]

  opts = [strategy: :one_for_one, name: MyApp.Supervisor]
  Supervisor.start_link(children, opts)
end

Subscribe to Database Changes

{:ok, channel} = MyApp.Realtime.channel("public:users")

# All changes on the users table
MyApp.Realtime.on(channel, "postgres_changes",
  event: :all, schema: "public", table: "users"
)

# Only inserts
MyApp.Realtime.on(channel, "postgres_changes",
  event: :insert, schema: "public", table: "users"
)

# With a filter
MyApp.Realtime.on(channel, "postgres_changes",
  event: :update, schema: "public", table: "users",
  filter: "id=eq.1"
)

Broadcast Messages

# Subscribe
MyApp.Realtime.on(channel, "broadcast", event: "new_message")

# Send
MyApp.Realtime.broadcast(channel, "new_message", %{body: "Hello!"})

Broadcast with Acknowledgment

{:ok, channel} = MyApp.Realtime.channel("room", broadcast: [ack: true])
:ok = MyApp.Realtime.on(channel, "broadcast", event: "msg")

{:ok, ack_ref} = MyApp.Realtime.broadcast_with_ack(channel, "msg", %{body: "hi"})

case MyApp.Realtime.wait_for_ack(ack_ref, timeout: 5000) do
  {:ok, :acknowledged} -> :delivered
  {:error, :timeout} -> :lost
end

Presence

# Track
MyApp.Realtime.track(channel, %{user_id: 123, online_at: DateTime.utc_now()})

# Get current state
MyApp.Realtime.presence_state()

# Untrack
MyApp.Realtime.untrack(channel)

HTTP Fallback

When the WebSocket is down, broadcast messages can be sent over HTTP:

{MyApp.Realtime, client: client, http_fallback: true}

Token Refresh

Provide a function to refresh tokens before each connection attempt:

{MyApp.Realtime,
  client: client,
  access_token_fn: fn -> MyApp.Auth.get_fresh_token() end}

Or update tokens at runtime:

MyApp.Realtime.set_auth("new-jwt-token")

Unsubscribe

MyApp.Realtime.unsubscribe(channel)
MyApp.Realtime.remove_all_channels()

Guides

References

License

This project is licensed under the MIT License - see the LICENSE file for details.

About

An isomorphic Elixir client for Supabase Realtime server

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Languages