notiqo
v0.2.4
Published
Notiqo CLI - scan repositories and generate analytics tracking plans
Maintainers
Readme
Notiqo CLI
notiqo scans a source repository, finds the analytics events it already sends
(Mixpanel, Amplitude, Segment, Firebase, PostHog, custom wrappers) and turns
them into a tagging guide that Notiqo can import. It is
deterministic, runs offline and fits in a CI job.
What it does — and what it does not
- Does: detect tracked events and their parameters from code, flag naming
issues, suggest missing events and funnels from industry templates, write
tracking-plan.md/tracking-plan.json/notiqo-guide.json, and push the guide into a Notiqo project through the same backend as@notiqo/mcp. - Does not: call any LLM. For AI-assisted guides (business context, event
definitions, measurement goals) use
@notiqo/mcpfrom Claude Code or Codex. The CLI covers what an agent does not do well repeatably: sweeping large repositories and running in CI.
Quick start
npx notiqo scan .That writes tracking-plan.md next to your code. To get the guide Notiqo
imports and preview the import without writing anything:
npx -y @notiqo/mcp login <project-id> # paste the token from Notiqo → Integrate → CLI token
npx notiqo scan . --format guide --only-existing --push --project <project-id>Add --yes to apply the plan. Without --yes a push is always a dry-run.
Requires Node.js 20 or newer.
Commands and options
notiqo scan [path] [options]| Option | Description | Default |
|--------|-------------|---------|
| --format <md\|json\|guide\|both> | Files to write: md, json, guide (notiqo-guide.json) or both (all three) | md |
| --only-existing | Emit only events detected in code, no suggestions (recommended for --push and CI) | false |
| --app-type <type> | Force the app type used for suggestions and funnels: ecommerce, saas, fintech, edtech, social, marketplace, content, telecom | auto-detect |
| --push | Plan the import of the guide into a Notiqo project (dry-run unless --yes) | false |
| --project <id> | Target Notiqo project (or NOTIQO_PROJECT_ID / .notiqo/config.json) | — |
| --yes | Apply the planned operations instead of only printing them | false |
| --json | With --push: print the plan as JSON on stdout; exit 1 if the planner reports issues | false |
| --token <token> | Notiqo token ntq_live_… (prefer login locally or NOTIQO_TOKEN in CI) | — |
Environment variables
| Variable | Purpose |
|----------|---------|
| NOTIQO_TOKEN | Token created in Notiqo → Integrate → CLI token. Overrides the token saved by login; an empty value or a literal ${NOTIQO_TOKEN} is ignored. Never commit it. |
| NOTIQO_PROJECT_ID | Default target project for --push. |
| NOTIQO_URL | Override the Notiqo Edge Functions base URL (local or staging). |
The project id can also live in the scanned repository as
.notiqo/config.json:
{ "projectId": "00000000-0000-4000-8000-000000000000" }Getting a token
- Open your Notiqo workspace → Integrate (in the sidebar) → CLI token.
- Click Create CLI token; it starts with
ntq_live_and is shown once. - On your machine, run
npx -y @notiqo/mcp login <project-id>(the dialog shows it with your project filled in) and paste the token. It is checked against Notiqo and saved in~/.notiqo/credentials.json, which both this CLI and the Notiqo MCP server read; no restart of Claude Code or Codex is needed. In CI, store it as theNOTIQO_TOKENsecret instead.
The token is resolved in this order: --token, a real NOTIQO_TOKEN, then the
token saved by login for the target project. It acts as you: it can only
write to projects where you have an editing role.
Push: how the import works
--push reuses the flow of @notiqo/mcp's notiqo_import_guide:
mcp-contextreads the target project (events, params, funnels, metrics, naming rules).- The guide is planned locally with the same Dart planner Notiqo's dashboard uses, and the dry-run report is printed: what will be created or updated, the GA4 dimension budget and what to review first.
- Only with
--yesare the operations sent tomcp-apply. Events land as drafts with an import origin, so they can be reviewed in Notiqo.
Events detected in code are imported with status existing and a code
reference (path:line). If the project does not have them yet, they are
created as drafts and the planner reports it as an issue — that is expected
on a first import.
Example
$ notiqo scan . --only-existing --push --project 1111-…
Notiqo Scan Results
===================
Detected framework: react
Existing tracked events: 3
...
Planning import into Notiqo project 1111-… (dry-run; add --yes to apply)...
# Dry-run de importación
...
### notiqo_propose_event — 3 (3 de alta, 0 de actualización)
- + purchase
- + add_to_cart
- + coupon_applied
...
Dry-run only: 8 operation(s) planned, nothing written. Re-run with --yes to apply.CI
A GitHub Actions job that fails when the scan finds events the plan does not know about, and applies the import on the default branch:
name: notiqo
on:
pull_request:
push:
branches: [main]
jobs:
tracking-plan:
runs-on: ubuntu-latest
env:
NOTIQO_TOKEN: ${{ secrets.NOTIQO_TOKEN }}
NOTIQO_PROJECT_ID: ${{ vars.NOTIQO_PROJECT_ID }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
# Dry-run on pull requests: the JSON plan is the job output.
- if: github.event_name == 'pull_request'
run: npx notiqo scan . --only-existing --push --json > notiqo-plan.json
- if: github.event_name == 'pull_request'
uses: actions/upload-artifact@v4
with:
name: notiqo-plan
path: notiqo-plan.json
# Apply on main.
- if: github.ref == 'refs/heads/main'
run: npx notiqo scan . --only-existing --push --yesWith --json stdout carries only { projectId, ops, issues, applied } and the
scan summary goes to stderr. The exit code is 1 whenever issues is not
empty, so review the artifact before treating a red job as a real problem.
Supported input
| Language / framework | Parsing | |----------------------|---------| | TypeScript, TSX, JavaScript, JSX (React, Next.js, Angular, Node) | tree-sitter AST, regex fallback for TS/TSX | | Dart (Flutter) | tree-sitter AST, regex fallback | | Python | tree-sitter AST | | Kotlin, Java (Android) | regex extractors |
Native tree-sitter grammars are optionalDependencies and are loaded only
when a file of that language is scanned. If a grammar fails to install (no
C++ toolchain, unsupported platform) the CLI still runs and warns that it is
using the regex extractors for that language.
Detected SDK patterns:
| SDK | Patterns |
|-----|----------|
| Firebase | .logEvent(name: 'event'), FirebaseAnalytics.instance.logEvent(...) |
| Mixpanel | mixpanel.track('event', {...}) |
| Amplitude | amplitude.track('event', {...}) |
| Segment | analytics.track('event', {...}) |
| PostHog | posthog.capture('event', {...}) |
| Custom | analytics.trackEvent(...), trackEvent(...), sendEvent(...) |
Output files
tracking-plan.md— human-readable: existing events, improvements, suggested events, funnels.tracking-plan.json— the same plan as data.notiqo-guide.json— the tagging guide, validated against the schema exported by@notiqo/mcp(@notiqo/mcp/schema.json). Events detected in code havestatus: "existing"and acodeRef; suggestions havestatus: "new"; params shared by three or more events becomeglobalParams.
Examples of the markdown and JSON output live in
docs/examples/.
Development
npm install
npm run build
npm test # vitest
npm run scan -- test/fixtures/react-mixpanelLayout:
src/
api/notiqo-client.ts HTTP client for mcp-context / mcp-apply
cli/ commander entry point and the scan command
core/ domain types, ports and the scan orchestrator
scanner/ tree-sitter factory, AST and regex extractors
event-generator/ rule-based suggestions and naming checks
funnel-detector/ industry funnel templates
guide/ TrackingPlan → guide, Dart planner, push flow
tracking-plan/ markdown/JSON rendering and file writing
test/ vitest suites and fixtures
docs/plans/ design notes (Spanish)License
MIT
