Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 111 additions & 0 deletions .github/workflows/analytics.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
name: Analytics

on:
pull_request:
paths:
- ".github/workflows/analytics.yml"
- "package.json"
- "pnpm-lock.yaml"
- "packages/local-docker/**"
- "packages/analytics/**"
- "packages/env/server.ts"
- "packages/web-backend/src/ProductAnalytics/**"
- "apps/web/actions/analytics/**"
- "apps/web/actions/organization/**"
- "apps/web/__tests__/unit/*analytics*.test.ts"
- "apps/web/__tests__/unit/developer-credits-webhook.test.ts"
- "apps/web/app/Layout/*Analytics*.tsx"
- "apps/web/app/api/events/**"
- "apps/web/app/api/invite/accept/route.ts"
- "apps/web/app/api/settings/billing/**"
- "apps/web/app/api/webhooks/stripe/route.ts"
- "apps/web/app/utils/analytics.ts"
- "apps/web/app/utils/product-analytics.ts"
- "apps/web/lib/analytics/**"
- "apps/web/lib/rate-limit.ts"
- "apps/desktop/src-tauri/src/lib.rs"
- "apps/desktop/src/utils/analytics.ts"
- "apps/desktop/src/utils/product-analytics.ts"
- "apps/desktop/src/utils/*analytics*.test.ts"
- "apps/desktop/src-tauri/src/posthog.rs"
- "scripts/analytics/**"
push:
branches:
- main
paths:
- ".github/workflows/analytics.yml"
- "package.json"
- "pnpm-lock.yaml"
- "packages/local-docker/**"
- "packages/analytics/**"
- "packages/env/server.ts"
- "packages/web-backend/src/ProductAnalytics/**"
- "apps/web/actions/analytics/**"
- "apps/web/actions/organization/**"
- "apps/web/__tests__/unit/*analytics*.test.ts"
- "apps/web/__tests__/unit/developer-credits-webhook.test.ts"
- "apps/web/app/Layout/*Analytics*.tsx"
- "apps/web/app/api/events/**"
- "apps/web/app/api/invite/accept/route.ts"
- "apps/web/app/api/settings/billing/**"
- "apps/web/app/api/webhooks/stripe/route.ts"
- "apps/web/app/utils/analytics.ts"
- "apps/web/app/utils/product-analytics.ts"
- "apps/web/lib/analytics/**"
- "apps/web/lib/rate-limit.ts"
- "apps/desktop/src-tauri/src/lib.rs"
- "apps/desktop/src/utils/analytics.ts"
- "apps/desktop/src/utils/product-analytics.ts"
- "apps/desktop/src/utils/*analytics*.test.ts"
- "apps/desktop/src-tauri/src/posthog.rs"
- "scripts/analytics/**"
workflow_dispatch:
inputs:
deploy:
description: Deploy the checked Tinybird project to production
required: true
default: false
type: boolean

permissions:
contents: read

jobs:
validate:
name: Validate and test analytics
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- uses: ./.github/actions/setup-js
- name: Run analytics regression suites
run: pnpm analytics:test
- name: Validate Docker Compose
run: node scripts/analytics/analytics-cli.js compose-check
- name: Build and test with Tinybird Local
run: node scripts/analytics/analytics-cli.js local
- name: Stop Tinybird Local
if: always()
run: node scripts/analytics/analytics-cli.js local-stop

deploy:
name: Deploy analytics
needs: validate
if: github.ref == 'refs/heads/main' && (github.event_name == 'push' || inputs.deploy == true)
runs-on: ubuntu-latest
timeout-minutes: 15
concurrency:
group: analytics-production
cancel-in-progress: false
environment: production
env:
TINYBIRD_DEPLOY_TOKEN: ${{ secrets.TINYBIRD_DEPLOY_TOKEN }}
TINYBIRD_URL: ${{ secrets.TINYBIRD_URL }}
TINYBIRD_WORKSPACE_ID: ${{ secrets.TINYBIRD_WORKSPACE_ID }}
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: 20
- name: Check and deploy Tinybird project
run: node scripts/analytics/analytics-cli.js cloud-deploy
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,17 @@ The web API uses Effect and `@effect/platform` HTTP APIs. Desktop capture and ex

## Analytics

Cap uses [Tinybird](https://www.tinybird.co) for viewer telemetry dashboards. Set `TINYBIRD_ADMIN_TOKEN` or `TINYBIRD_TOKEN` before running analytics commands.
Cap uses [Tinybird](https://www.tinybird.co) for product and viewer analytics. The product event collector uses a separate append-only token, while agents use read-only query access.

| Command | Purpose |
| --- | --- |
| `pnpm analytics:setup` | Deploy Tinybird datasources and pipes from `scripts/analytics/tinybird` |
| `pnpm analytics:local` | Start the optional Tinybird Local Docker profile, build resources, run fixtures, and write `.env.analytics.local` |
| `pnpm analytics:test` | Run deterministic infrastructure tests and static validation |
| `pnpm analytics:deploy:check` | Validate a cloud deployment without promoting it |
| `pnpm analytics:deploy` | Safely deploy checked-in Tinybird resources |
| `pnpm analytics:check` | Validate that the Tinybird workspace matches the app expectations |

`analytics:setup` can remove Tinybird resources outside the checked-in analytics configuration. Use it only against the workspace you intend to manage from this repo.
Routine analytics commands reject destructive operations. See [scripts/analytics/README.md](scripts/analytics/README.md) for local setup, scoped credentials, deployment, and agent access.

## Contributing

Expand Down
1 change: 1 addition & 0 deletions apps/desktop/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
},
"dependencies": {
"@aerofoil/rive-solid-canvas": "^2.1.4",
"@cap/analytics": "workspace:*",
"@cap/database": "workspace:*",
"@cap/ui-solid": "workspace:*",
"@cap/utils": "workspace:*",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5184,6 +5184,7 @@ pub async fn run(recording_logging_handle: LoggingHandle, logs_dir: PathBuf) {
specta_builder.mount_events(&app);
hotkeys::init(&app);
general_settings::init(&app);
posthog::init_product_session(&app);
configure_camera_blur_recovery(&app, previous_termination);
fake_window::init(&app);
app.manage(target_select_overlay::WindowFocusManager::default());
Expand Down
Loading
Loading