{"id":13368231,"url":"https://github.com/supabase/realtime-py","last_synced_at":"2025-05-15T01:04:39.488Z","repository":{"id":37012111,"uuid":"297576738","full_name":"supabase/realtime-py","owner":"supabase","description":"A Python Client for Phoenix Channels ","archived":false,"fork":false,"pushed_at":"2025-05-13T17:22:57.000Z","size":582,"stargazers_count":154,"open_issues_count":5,"forks_count":57,"subscribers_count":26,"default_branch":"main","last_synced_at":"2025-05-13T18:37:04.486Z","etag":null,"topics":["community","python","realtime","supabase"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/supabase.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["supabase"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"custom":null}},"created_at":"2020-09-22T07:56:30.000Z","updated_at":"2025-05-08T14:25:38.000Z","dependencies_parsed_at":"2023-12-02T02:27:18.106Z","dependency_job_id":"af8be64e-ad4d-424d-a1eb-e05c8661f720","html_url":"https://github.com/supabase/realtime-py","commit_stats":{"total_commits":185,"total_committers":30,"mean_commits":6.166666666666667,"dds":0.7135135135135136,"last_synced_commit":"049d185fc36c149b086a6196ea26e4ebf1410f18"},"previous_names":["supabase/realtime-py"],"tags_count":22,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase%2Frealtime-py","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase%2Frealtime-py/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase%2Frealtime-py/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/supabase%2Frealtime-py/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/supabase","download_url":"https://codeload.github.com/supabase/realtime-py/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254250330,"owners_count":22039197,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["community","python","realtime","supabase"],"created_at":"2024-07-30T01:00:54.238Z","updated_at":"2025-05-15T01:04:39.433Z","avatar_url":"https://github.com/supabase.png","language":"Python","funding_links":["https://github.com/sponsors/supabase"],"categories":["Realtime","Python"],"sub_categories":[],"readme":"\u003cbr /\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://supabase.io\"\u003e\n        \u003cpicture\u003e\n      \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://raw.githubusercontent.com/supabase/supabase/main/packages/common/assets/images/supabase-logo-wordmark--dark.svg\"\u003e\n      \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://raw.githubusercontent.com/supabase/supabase/main/packages/common/assets/images/supabase-logo-wordmark--light.svg\"\u003e\n      \u003cimg alt=\"Supabase Logo\" width=\"300\" src=\"https://raw.githubusercontent.com/supabase/supabase/main/packages/common/assets/images/logo-preview.jpg\"\u003e\n    \u003c/picture\u003e\n  \u003c/a\u003e\n\n  \u003ch1 align=\"center\"\u003eSupabase Realtime Client\u003c/h1\u003e\n\n  \u003ch3 align=\"center\"\u003eSend ephemeral messages with \u003cb\u003eBroadcast\u003c/b\u003e, track and synchronize state with \u003cb\u003ePresence\u003c/b\u003e, and listen to database changes with \u003cb\u003ePostgres Change Data Capture (CDC)\u003c/b\u003e.\u003c/h3\u003e\n\n  \u003cp align=\"center\"\u003e\n    \u003ca href=\"https://supabase.com/docs/guides/realtime\"\u003eGuides\u003c/a\u003e\n    ·\n    \u003ca href=\"https://supabase.com/docs/reference/python\"\u003eReference Docs\u003c/a\u003e\n    ·\n    \u003ca href=\"https://multiplayer.dev\"\u003eMultiplayer Demo\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/p\u003e\n\n# Overview\n\nThis client enables you to use the following Supabase Realtime's features:\n\n- **Broadcast**: send ephemeral messages from client to clients with minimal latency. Use cases include sharing cursor positions between users.\n- **Presence**: track and synchronize shared state across clients with the help of CRDTs. Use cases include tracking which users are currently viewing a specific webpage.\n- **Postgres Change Data Capture (CDC)**: listen for changes in your PostgreSQL database and send them to clients.\n\n# Usage\n\n## Installing the Package\n\n```bash\npip3 install realtime\n```\n\n## Creating a Channel\n\n```python\nimport asyncio\nfrom typing import Optional\n\nfrom realtime import AsyncRealtimeClient, RealtimeSubscribeStates\n\n\nasync def main():\n    REALTIME_URL = \"ws://localhost:4000/websocket\"\n    API_KEY = \"1234567890\"\n\n    socket = AsyncRealtimeClient(REALTIME_URL, API_KEY)\n    channel = socket.channel(\"test-channel\")\n\n    def _on_subscribe(status: RealtimeSubscribeStates, err: Optional[Exception]):\n        if status == RealtimeSubscribeStates.SUBSCRIBED:\n            print(\"Connected!\")\n        elif status == RealtimeSubscribeStates.CHANNEL_ERROR:\n            print(f\"There was an error subscribing to channel: {err.args}\")\n        elif status == RealtimeSubscribeStates.TIMED_OUT:\n            print(\"Realtime server did not respond in time.\")\n        elif status == RealtimeSubscribeStates.CLOSED:\n            print(\"Realtime channel was unexpectedly closed.\")\n\n    await channel.subscribe(_on_subscribe)\n```\n\n### Notes:\n\n- `REALTIME_URL` is `ws://localhost:4000/socket` when developing locally and `wss://\u003cproject_ref\u003e.supabase.co/realtime/v1` when connecting to your Supabase project.\n- `API_KEY` is a JWT whose claims must contain `exp` and `role` (existing database role).\n- Channel name can be any `string`.\n\n## Broadcast\n\nYour client can send and receive messages based on the `event`.\n\n```python\n# Setup...\n\nchannel = client.channel(\n    \"broadcast-test\", {\"config\": {\"broadcast\": {\"ack\": False, \"self\": False}}}\n)\n\nawait channel.on_broadcast(\"some-event\", lambda payload: print(payload)).subscribe()\nawait channel.send_broadcast(\"some-event\", {\"hello\": \"world\"})\n```\n\n### Notes:\n\n- Setting `ack` to `true` means that the `channel.send` promise will resolve once server replies with acknowledgement that it received the broadcast message request.\n- Setting `self` to `true` means that the client will receive the broadcast message it sent out.\n- Setting `private` to `true` means that the client will use RLS to determine if the user can connect or not to a given channel.\n\n## Presence\n\nYour client can track and sync state that's stored in the channel.\n\n```python\n# Setup...\n\nchannel = client.channel(\n    \"presence-test\",\n    {\n        \"config\": {\n            \"presence\": {\n                \"key\": \"\"\n            }\n        }\n    }\n)\n\nchannel.on_presence_sync(lambda: print(\"Online users: \", channel.presence_state()))\nchannel.on_presence_join(lambda new_presences: print(\"New users have joined: \", new_presences))\nchannel.on_presence_leave(lambda left_presences: print(\"Users have left: \", left_presences))\n\nawait channel.track({ 'user_id': 1 })\n```\n\n## Postgres CDC\n\nReceive database changes on the client.\n\n```python\n# Setup...\n\nchannel = client.channel(\"db-changes\")\n\nchannel.on_postgres_changes(\n    \"*\",\n    schema=\"public\",\n    callback=lambda payload: print(\"All changes in public schema: \", payload),\n)\n\nchannel.on_postgres_changes(\n    \"INSERT\",\n    schema=\"public\",\n    table=\"messages\",\n    callback=lambda payload: print(\"All inserts in messages table: \", payload),\n)\n\nchannel.on_postgres_changes(\n    \"UPDATE\",\n    schema=\"public\",\n    table=\"users\",\n    filter=\"username=eq.Realtime\",\n    callback=lambda payload: print(\n        \"All updates on users table when username is Realtime: \", payload\n    ),\n)\n\nchannel.subscribe(\n    lambda status, err: status == RealtimeSubscribeStates.SUBSCRIBED\n    and print(\"Ready to receive database changes!\")\n)\n```\n\n## Get All Channels\n\nYou can see all the channels that your client has instantiated.\n\n```python\n# Setup...\n\nclient.get_channels()\n```\n\n## Cleanup\n\nIt is highly recommended that you clean up your channels after you're done with them.\n\n- Remove a single channel\n\n```python\n# Setup...\n\nchannel = client.channel('some-channel-to-remove')\n\nchannel.subscribe()\n\nawait client.remove_channel(channel)\n```\n\n- Remove all channels\n\n```python\n# Setup...\n\nchannel1 = client.channel('a-channel-to-remove')\nchannel2 = client.channel('another-channel-to-remove')\n\nawait channel1.subscribe()\nawait channel2.subscribe()\n\nawait client.remove_all_channels()\n```\n\n## Credits\n\nThis repo draws heavily from [phoenix-js](https://github.com/phoenixframework/phoenix/tree/master/assets/js/phoenix).\n\n## License\n\nMIT.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase%2Frealtime-py","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsupabase%2Frealtime-py","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsupabase%2Frealtime-py/lists"}