Schedule icon
Select icon
Query icon
If icon
SlackIncomingWebhook icon
Log icon

Supabase Analytics Pipeline with DuckDB In-Memory Aggregations and Slack Metric Digest

Extract user telemetry from Supabase, run SQL aggregations in DuckDB, and send automated metric summaries to Slack with Kestra.

Categories
BusinessCloudData

Automate weekly analytics reporting on Supabase user event telemetry. This workflow extracts activity records via PostgREST, performs in-memory SQL aggregations with DuckDB, and delivers a metric digest to Slack.

What you get

  • Automated weekly event metrics digest delivered to Slack.
  • Zero-footprint in-memory SQL aggregations using DuckDB.
  • Automatic handling for empty event windows using flow conditional branching.

Prerequisites

  • A Supabase project with an analytics or telemetry event table.
  • A Slack incoming webhook URL for notifications.
  • Note on Supabase Row Cap: PostgREST caps single-request REST queries to 1,000 rows by default.

Secrets

  • SUPABASE_API_KEY: Your Supabase API key.
    • Role note: Use the service_role key to bypass Row Level Security (RLS), or the anon key if your RLS policies explicitly allow public read access to the telemetry table.
  • SLACK_WEBHOOK_URL: Incoming Webhook URL configured in your Slack workspace.

Quick start

  1. Run the seed SQL below in the Supabase SQL editor.
  2. Add the SUPABASE_API_KEY and SLACK_WEBHOOK_URL secrets.
  3. Set supabase_url to your project URL and run the flow manually.

Expected output

  • extract_events writes the fetched rows to {{ outputs.extract_events.uri }}.
  • analyze_metrics returns one row per event type in {{ outputs.analyze_metrics.rows }} (event_type, active_users, total_events).
  • Slack receives a digest with the number of event categories and the top event. With the seed data, page_view comes first with 2 events from 2 active users.

Seed SQL

To set up the sample user_events table in your Supabase SQL Editor:

CREATE TABLE IF NOT EXISTS public.user_events (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL,
    event_type TEXT NOT NULL,
    channel TEXT DEFAULT 'web',
    created_at TIMESTAMPTZ DEFAULT now()
);

INSERT INTO public.user_events (user_id, event_type, channel, created_at) VALUES
    ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'page_view', 'web', now() - interval '2 days'),
    ('a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11', 'button_click', 'web', now() - interval '2 days'),
    ('b1eebc99-9c0b-4ef8-bb6d-6bb9bd380a22', 'page_view', 'mobile', now() - interval '1 day'),
    ('b1eebc99-9c0b-4ef8-bb6d-6bb9bd380a22', 'checkout_start', 'mobile', now() - interval '1 day'),
    ('c2eebc99-9c0b-4ef8-bb6d-6bb9bd380a33', 'checkout_complete', 'web', now());

Links

See How

New to Kestra?

Use blueprints to kickstart your first workflows.