Supabase Integration
Skene connects to your Supabase organization via OAuth, then you assign the projects it reads: a Development Database, a Production Database, or both. The default and recommended mode is read-only: Skene reads only your schema, the table, column, and type definitions, and never reads row data or writes to your database.
That schema grounds lifecycle analysis and the lifecycle map Skene builds for your workspace. The connection gives you schema, not row values and not runtime behavior.
The OAuth connection is one of three Supabase relationships. The second is the analytics destination: storage in your own Supabase where Skene writes the skene.track() events your product sends. The third is Supabase Pipeline data: the tables your plans measure, prepared for replication into a warehouse.
An optional read-write mode lets Skene read table counts (the database half of the live numbers on the Lifecycle page; event counts come from the analytics destination or a connected PostHog or Mixpanel source, no read-write needed) and deploy automation triggers into your database (see Automations below).
How it works (read-only)
- Connect: Link your Supabase organization via OAuth from Settings → Supabase. Connections start read-only.
- Assign your databases: the connection has two independent slots, Development Database and Production Database. Assign any project or branch the OAuth grant can see to either one; dev and preview branches appear in the same list, labeled with their parent project and git branch.
- Ground: Skene reads the schema and grounds lifecycle analysis against it.
Prerequisites
- A Supabase project
- A Skene workspace
- Optionally, for read-write mode only: the
pg_netextension enabled in your Supabase project (used by deployed triggers to send webhooks)
Connect your Supabase project
1. Open Settings → Supabase
In the workspace sidebar, open Settings and pick the Supabase tab. You can also go directly to /workspace/<your-slug>/settings?tab=supabase, or click Connect on the Supabase card on the Overview page.
2. Connect (read-only)
Click Connect Supabase. You will be redirected to Supabase to authorize. Connections always start read-only; you can upgrade later if you need more (see Switching access mode).
The two access levels:
| Mode | What it allows | When to use |
|---|---|---|
| Read-only | Schema introspection. No row data, no table counts | Default. Grounding lifecycle analysis |
| Read-write | Schema introspection + table counts + trigger deployment | Optional. Automations and live step counts (see below) |
3. Assign Development and Production Database
After authorizing, you will be redirected back to Skene. The OAuth grant is what lists your projects; which project Skene reads is a separate, per-environment choice.
Two cards appear, Development Database and Production Database (workspace owners only). For each one, pick a project or branch from the dropdown and click Use as Development Database or Use as Production Database. Remove clears that slot without touching the OAuth connection or the other slot.
You do not have to fill both. Leaving one unused is fine: measurement checks report that environment as not linked, and the other environment carries on.
4. Verify connection
Once linked, the same tab shows your connection status:
- A Supabase connection panel with the access mode (read-only or read-write) and how it was connected
- The Development Database and Production Database cards, each showing the assigned project ref and URL, or "Not assigned"
Disconnecting and testing the connection happen in the same tab.
Analytics destination
The OAuth connection reads your schema. The Analytics destination is the write side: an Analytics Bucket in your own Supabase Storage where Skene lands the skene.track() events your product sends, as Iceberg/Parquet tables you own (default.events). Rollups over that bucket feed the live event counts on the Lifecycle page. The full pipeline is in Product analytics that live in your own Supabase.
Set it up from the same Settings → Supabase tab, below the connection card (workspace owners only). It's separate from the OAuth connection and can point at a different Supabase project. Paste credentials from that project's dashboard:
| Field | Where it comes from |
|---|---|
| Project ref | Defaults to your Production Database, or your Development Database if only that one is assigned; change it to target another project |
| Bucket name | Defaults to skene-analytics |
| API secret key | Project Settings → API: the service_role key, not the anon/public key |
| S3 access key ID + secret | Storage → S3 access keys |
| S3 region | The same Storage settings (defaults to us-east-1) |
Check Create bucket to have Skene create the Analytics Bucket if it doesn't exist yet. Credentials are encrypted and used only by the server; they're never shown again after saving.
Once connected, the card shows Sync status: when it last synced, events in the last sync, and whether long-term storage loaded or was skipped.
Advanced: verify with DuckDB
The card includes a copy-paste DuckDB query that attaches the bucket and counts events by name, so you can confirm data is landing in skene_analytics.default.events. Replace the credential placeholders with the keys you saved above, then run it in the DuckDB CLI or a notebook.
Supabase Pipeline data
When a plan links a product table as a data change, that table is registered for replication out of Postgres. The Supabase Pipeline data card on the Integrations page is where that lands.
The card lists every selected table with its columns and a publication status: Recommended, Selected, In publication, Restart required, Syncing, Live, or Blocked (blocked tables show the reason). Re-check re-reads readiness from the database, and Remove takes a table out of the selection. Plans that relied on a removed table lose their measurement input.
Below the list, Data destination is where the warehouse goes (workspace owners only): BigQuery, ClickHouse, Snowflake, and DuckLake are shown, and all four are marked Coming soon today. Publication, replication, and warehouse setup stay on this page; Skene links out to Replication in the Supabase dashboard when a publication change needs a Pipeline restart.
Until a destination is available, checks read the measurement tables straight from the linked Development and Production Databases.
Automations (read-write mode)
The sections below cover the optional read-write mode, where Skene deploys automation triggers into your database and can read table counts for live numbers on the Lifecycle page. This is separate from the read-only mode described above, and none of it is required for the lifecycle or tracking. Skip it if you only need schema grounding.
Schema setup
The first time you deploy, the deploy wizard checks for the skene_growth schema in your Supabase project. If it's missing, the wizard adds a schema setup step where you apply the migrations yourself (one for the tables, one for the webhook). Nothing is installed silently. The schema contains:
| Object | Purpose |
|---|---|
skene_growth.schema_meta | Records the installed schema version |
skene_growth.event_log | Captures trigger payloads before they are sent to Skene |
skene_growth.failed_events | Stores events that failed to dispatch |
skene_growth.enrichment_map | JSON-based data joins for adding context to events |
skene_growth.enrich_event() | Resolves enrichment maps as events land in the log |
skene_growth.notify_event_log() | Sends each logged event to Skene via pg_net |
Deploying triggers
From the Actions page
- Create or select an automation on the Actions page.
- Compile. Skene introspects your schema and generates a state machine.
- Deploy. The deploy wizard checks your Supabase link, walks you through schema setup if needed, analyzes the automation, and shows a review step before pushing the trigger SQL to your Supabase project via the OAuth token.
What gets deployed
For each target table and operation (e.g., INSERT on auth.users), a deploy creates:
- A trigger function named
skene_growth_fn_<table>_<op>, created in your database's default schema (typicallypublic) - A trigger named
skene_growth_trg_<table>_<op>on the target table
When a row changes, the trigger writes the row into skene_growth.event_log. There, enrich_event() resolves any enrichment maps, and notify_event_log() calls net.http_post() (from pg_net) to send the event to your workspace's ingest endpoint. Requests authenticate with a per-workspace secret (skene_proxy_secret), encrypted at rest with AES-256-GCM.
Trigger reconciliation
Skene automatically reconciles triggers on each compile/deploy cycle:
- Adds triggers for new or updated automations
- Removes orphan triggers no longer referenced by any automation
- Deduplicates: multiple automations on the same table and operation share one trigger
Event flow
Your Supabase database
└─ Row change fires skene_growth_trg_<table>_<op>
└─ Row logged to skene_growth.event_log (enrich_event() adds context)
└─ pg_net POST -> <your workspace endpoint>/api/v1/cloud/ingest/db-trigger
└─ Skene runtime
├─ Log raw event
├─ Match to automations (conditions, cooldowns, state checks)
├─ Execute actions (email, webhook, state transition)
└─ Update journey state and logs
Events are authenticated via the x-skene-secret header, matched against the workspace's encrypted proxy secret.
Premade templates
Three templates are available to get started quickly:
| Template | Trigger | Action |
|---|---|---|
| Triggerbeat | New record inserted | Fire analytics event |
| Welcome Email Drip | New user signup (INSERT on your user table) | Send welcome email |
| Inactivity Re-engagement | Scheduled daily via pg_cron (7+ days inactive) | Send re-engagement email |
Monitoring
Logs
The Logs page in your workspace shows:
- Raw ingest records with timestamps
- Which automations matched each event and why
- Action dispatch results (success, failure, skipped)
- Semantic matcher audit trails for edge cases
Trigger status
The Actions page shows each automation's deploy status, last deployed timestamp, and linked trigger ID.
Security
- OAuth tokens are encrypted with AES-256-GCM and stored in Skene's database, never in browser storage.
- Proxy secrets authenticate ingest webhooks. Each workspace has a unique secret.
- No customer data stored beyond event metadata needed for dispatch decisions.
- Read-only mode available for lifecycle analysis without deployment risk.
Disconnecting
There are three separate disconnects, all in Settings → Supabase:
- Remove on a Development Database or Production Database card: clears that one slot. The OAuth connection, the other slot, and your database are untouched. Checks report the cleared environment as not linked.
- Disconnect (the OAuth connection): clears both environment slots and deletes the connection and its OAuth tokens from Skene. It does not touch your database: deployed triggers, trigger functions, and the
skene_growthschema stay in place. - Disconnect destination (the analytics destination): stops Skene writing events to the bucket until you reconnect, and removes the stored bucket credentials from Skene. The bucket itself and the events already in it stay in your Supabase, untouched. This doesn't affect the OAuth connection, and vice versa.
To clean up deployed objects, note that dropping the schema alone is not enough. Trigger functions live in your default schema and the triggers sit on your own tables, so they survive a schema drop (they no-op safely, but they stick around). Remove them first:
-- Find Skene triggers on your tables
SELECT event_object_schema, event_object_table, trigger_name
FROM information_schema.triggers
WHERE trigger_name LIKE 'skene_growth_trg_%';
-- For each result, drop the trigger and its function
-- (function name = trigger name with trg replaced by fn)
DROP TRIGGER <trigger_name> ON <schema>.<table>;
DROP FUNCTION <function_name>();
-- Then drop the schema
DROP SCHEMA IF EXISTS skene_growth CASCADE;
-- If you used Inactivity Re-engagement, also remove its cron job
SELECT cron.unschedule('skene_check_inactive');
Switching access mode
You don't need to disconnect. If the connection is read-only, Skene asks for the upgrade at the point you need it: deploying an automation or turning on a trigger opens a Read-write Supabase connection needed dialog with an Upgrade to Read + Write button. You re-authorize with Supabase and the connection upgrades in place, keeping your project assignments and webhook secret. To go back to read-only, disconnect and reconnect in read-only mode.
Troubleshooting
Schema setup fails with a pg_net error
Skene doesn't check pg_net ahead of time; the error surfaces when the webhook migration runs during schema setup. Enable the extension in Supabase (Database → Extensions → Search for pg_net → Enable), then retry the step.
Triggers not firing
- Check that the automation is in Active status (not Draft or Paused).
- Verify the trigger exists in your database. Triggers attach to your own tables, so search by name, not by schema:
SELECT trigger_name FROM information_schema.triggers WHERE trigger_name LIKE 'skene_growth_trg_%'; - Check the Logs page for ingest errors.
OAuth token expired
Skene refreshes OAuth tokens automatically whenever the connection is used. If auth errors persist, reconnect from Settings → Supabase.
Next steps
- Push: Push journeys and action definitions from the CLI
- MCP Server: Use skene with AI assistants
- Configuration: Config files and environment variables