If you already use PostHog to capture events, register using your PostHog project id as the product_id and skip to step 3You can find your PostHog Project ID (often referred to as a Team ID) through the following methods:
URL: The easiest way to find it is to look at the URL while logged into your project. The numeric value following /project/ in the address bar is your Project ID.
Project Settings: Navigate to Project Settings in the PostHog sidebar. The ID is typically listed under the general project configuration or API sections.
๐ป Step 2 โ Add the front end snippet to capture events
Next, we are going to add a tiny piece of tracking code (powered by PostHog) to your website. This acts as the โeyesโ that see what users are clicking on.Use your PostHog Project API Key (starts with phc_) here. Personal keys (phx_...) are admin keys and posthog.init() rejects them with personal_api_key.Copy the code snippet below into your websiteโs frontend. Make sure to replace YOUR_POSTHOG_PROJECT_API_KEY and YOUR_PRODUCT_ID with your real values.JavaScript
import posthog from 'posthog-js'posthog.init('YOUR_POSTHOG_PROJECT_API_KEY', { api_host: 'https://us.i.posthog.com', person_profiles: 'identified_only', // This stops recording if a user walks away for 2 minutes, keeping your data clean: session_idle_timeout_seconds: 120, loaded: (posthog) => { posthog.identify(posthog.get_distinct_id(), { // Autoplay-specific field. Must match onboard_product(product_id=...). product_id: 'YOUR_PRODUCT_ID', }); },})
Highly Recommended: Tag users when they log in If a user logs into your app, you can tell Autoplay who they are. This automatically links their web activity to their chatbot conversations, no extra work required. Just run this code right after your login process finishes:
posthog.identify(user.id, { product_id: 'YOUR_AUTOPLAY_PRODUCT_ID', email: user.email, // Added to the person profile and the $identify event.})// If you want payload.email on ongoing autocapture events, also register email as a super-property.posthog.register({ email: user.email })
(Note: If you donโt provide an email, anonymous users will still be tracked.)
๐ Quick Tip: Once you add this code to your site, jump into our Slack workspace and drop a message in #just-integrated. We will check to make sure your data is flowing properly and help you get fully set up!
Identity plumbing for widget-based chatbots: make sure the same user identity flows across all three layers: PostHog distinct_id / user_id, your chat widget session metadata, and the chatbot backend sender identifier. If those do not match, chat replies will look like โno recent activityโ because events are stored under one key and fetched with another.
๐ Step 3 โ Registering your product with Autoplay
Now that your website is tracking clicks, we need to create a secure โmailing addressโ (Webhook URL) and a shared secret (X-PostHog-Secret) so that data can be safely sent to Autoplay.Registration requires a valid contact email (stored on your connector product row) in addition to your product id. Existing deployments may still have older product rows without email until you re-register.Your stream consumer can pass the bearer token directly to AsyncConnectorClient(token=...) or via AUTOPLAY_APP_UNKEY_TOKEN.
If you already use PostHog, register using your PostHog project id as the product_idYou can find your PostHog Project ID (often referred to as a Team ID) through the following methods:
URL: The easiest way to find it is to look at the URL while logged into your project. The numeric value following /project/ in the address bar is your Project ID.
Project Settings: Navigate to Project Settings in the PostHog sidebar. The ID is typically listed under the general project configuration or API sections.
Run the following script:1. Install the Toolkit (Requires Python 3.10+) Open your computerโs terminal and install our SDK using either command:Bash
pip install autoplay-sdk# ORuv add autoplay-sdk
โก Set up Cursor / Claude AI skills (optional but recommended)The SDK ships with agent skills for Cursor and Claude that teach your AI assistant exactly how to wire Autoplay for your specific chatbot and activity source โ including the session scoping patterns that most integrations get wrong.Run this once after installing the SDK, from your project root:
autoplay-install-skills
Existing skill directories are preserved by default. Pass --force only if you intentionally want to overwrite local changes.Or target your specific stack:
This drops a .cursor/skills/ folder into your project. Then just open Cursor or Claude and say:
โSet up Autoplay with Ada and FullStoryโ
The agent will follow the correct wiring pattern โ session scoping, conversation linking, field mapping โ automatically.
2. Run the Registration Script Create a Python file with the code below. Paste your Product ID from Step 1 into the script and run it.Python
import asynciofrom autoplay_sdk.admin import onboard_productasync def main() -> None: result = await onboard_product( "YOUR_AUTOPLAY_PRODUCT_ID", contact_email="you@yourcompany.com", print_operator_summary=True, ) # result still has the same full fields if you need them in codeasyncio.run(main())
Now we must tell the website tracker (Step 2) to send its data to the secure address (webhook) you just generated (Step 3).You have two choices:Option A โ Managed (default)
๐ก Step 5 โ Watch Your Data Arrive Live! (Receive your first event)
Everything is wired up! Letโs turn on the monitor to see a live feed of your usersโ actions.Run this final script. If you used the DIY method in Step 4, use the Stream URL from Step 3 and your Unkey token. If we helped you in Slack, use the stream URL and API token from Autoplayโs 1Password handoff.Then run the script, it connects to the SSE endpoint and prints every event as it arrives.Python
import asynciofrom autoplay_sdk import AsyncConnectorClient# Paste your Stream URL and Token here!STREAM_URL = "https://your-connector.onrender.com/stream/YOUR_PRODUCT_ID"API_TOKEN = "unkey_xxxx..."# You can also set AUTOPLAY_APP_UNKEY_TOKEN in your environment.def on_actions(p): print("\n=== LIVE USER ACTIONS ===") print(f" Session ID : {p.session_id}") print(f" User ID : {p.user_id}") print(f" Product ID : {p.product_id}") print(f" Total Clicks : {p.count}") print(f" Time Received: {p.forwarded_at}") for i, action in enumerate(p.actions): print(f" [{i}] Action: {action.title}") print(f" Details: {action.description}") print(f" Page: {action.canonical_url}")def on_summary(p): print("\n=== AI SUMMARY ===") print(f" Session ID : {p.session_id}") print(f" Product ID : {p.product_id}") print(f" Summarizes : {p.replaces} actions") print(f" Summary text : {p.summary}")async def main(): async with AsyncConnectorClient(url=STREAM_URL, token=API_TOKEN) as client: client.on_actions(on_actions) client.on_summary(on_summary) print("Listening for live website clicks... (Press Ctrl+C to stop)") await client.run()asyncio.run(main())
(Note: If your internet drops, the client will reconnect automatically. Press Ctrl+C to stop listening.)What you will see: When you click around your app, your terminal will instantly populate with an AI summary of exactly what you are doing, looking something like this:Plaintext
=== ACTIONS === session_id : ps_abc123 user_id : user_xyz product_id : acme-corp count : 3 forwarded_at : 1736940685.103 [0] title : Page Load: Dashboard description : User landed on the main Dashboard page canonical_url: <https://app.example.com/dashboard> [1] title : Click Export CSV description : User clicked the Export CSV button canonical_url: <https://app.example.com/dashboard> [2] title : Click Settings description : User clicked the Settings link in the sidebar canonical_url: <https://app.example.com/dashboard>=== SUMMARY === session_id : ps_abc123 product_id : acme-corp replaces : 12 actions forwarded_at : 1736940750.881 summary : User explored the Dashboard, exported a CSV, and navigated to billing settings.
This output comes from the example scriptโs print(...) statements. SDK callbacks still receive typed dataclasses (ActionsPayload / SummaryPayload).
Now that your data is flowing, hereโs how to put it to work:
Typed Payloads: Explore all available fields for Actions and Summaries.
Inject into your LLM Response: Pass real-time user events into your prompt so the LLM understands what a user just didโnot just what they asked. Most users are in the wrong part of your product when they ask for help; this is what lets your copilot bridge that gap.
Agentic RAG: Build agents that track where a user is, where they need to be, and guide them thereโโYouโve been on this page for a few minutesโhereโs where you actually need to go.โ
Async Client: Use Autoplay alongside LangChain or FastAPI.
Typed payloads
Explore all fields on ActionsPayload and SummaryPayload
RAG pipeline
Embed events into a vector store in real time
Async client
Use AsyncConnectorClient with LangChain or FastAPI
Proactive copilot
Combine real-time events, memory, and golden paths
Chatbot tutorials
Step-by-step guides for Intercom, Ada, Botpress, and more
AI agent skills
Install Cursor / Claude skills with autoplay-install-skills
For structured logging and extra field conventions used across the SDK, see Logging. Release history is on the Changelog.