CLI
The g8 CLI gives you terminal access to graph8’s developer tools — get framework-specific tracking snippets and progressive form templates directly from your terminal.
Personal vs Admin Credentials
For most users, CLI auth should come from your Profile.
| Use Case | Where to get credentials | What to use |
|---|---|---|
| Personal CLI usage on your machine | Profile -> Developer | g8 login (OAuth) or personal API key |
| Shared service account or org-wide automation | Settings -> API | Org API key |
Installation
pip install g8-mcp-serverThis installs the g8 command. Requires Python 3.10+.
Authentication
Three ways to authenticate:
g8 login (recommended)
g8 loginOpens your browser to sign in via OAuth. Once authenticated, a token is saved to ~/.g8/credentials.json and used automatically for all future commands. No API key needed.
API key
If you prefer using an API key, use your personal API key from Profile -> Developer. Admins can also use org keys from Settings -> API for shared integrations.
Store it locally:
g8 login --api-keyPrompts you to paste an API key, validates it, and saves it to ~/.g8/credentials.json.
Or set it as an environment variable:
export G8_API_KEY="your_api_key_here"g8 logout
Remove stored credentials:
g8 logoutg8 whoami
Check your current authentication status:
g8 whoami# Auth source: OAuth (~/.g8/credentials.json)# Logged in as: thomas@graph8.comCommands
g8 snippet
Get the graph8 tracking snippet for any supported framework. The snippet loads p.js — the graph8 tracking script — on every page.
Usage:
# Get snippet for a frameworkg8 snippet --framework nextjs
# List all supported frameworksg8 snippet --list
# Get snippet for a specific repog8 snippet --framework react --repo-id <repo-id>
# Output as JSONg8 snippet --framework html --format jsonOptions:
| Option | Description |
|---|---|
--framework | Target framework (required unless --list) |
--list | List all supported frameworks |
--repo-id | Repository ID for repo-specific config (optional) |
--format | Output format: text (default) or json |
Supported Frameworks:
| Framework | Rendering | Description |
|---|---|---|
html | SSR | HTML / Vanilla JS — script tag in <head> |
react | CSR | React — useEffect component |
nextjs | SSR | Next.js — next/script for App Router and Pages Router |
vue | CSR | Vue — onMounted composable |
wordpress | SSR | WordPress — functions.php hook |
webflow | SSR | Webflow — Custom Code in project settings |
shopify | SSR | Shopify — theme.liquid snippet |
Example output:
$ g8 snippet --framework nextjsgraph8 Tracking Snippet — Next.js
Setup Steps: 1. App Router: add the Script to app/layout.tsx 2. Pages Router: add the Script to pages/_app.tsx 3. Use window.g8?.track() and window.g8?.identify() in client components
Code:————————————————————————————————————————————————————————————// app/layout.tsx (App Router)import Script from 'next/script';
export default function RootLayout({ children }) { return ( <html> <head> <Script src="https://t.graph8.com/p.js" data-write-key="your-write-key" data-tracking-host="https://t.graph8.com" strategy="afterInteractive" /> </head> <body>{children}</body> </html> );}————————————————————————————————————————————————————————————
Tracking Methods: identify: g8.identify("user-id", {email: "user@example.com", name: "Jane Doe"}) track: g8.track("event_name", {property: "value"})Privacy Options
The generated snippet includes data-attributes you can add to control privacy behavior:
| Attribute | Values | Description |
|---|---|---|
data-privacy-dont-send | "true" | Disables cookies and event sending |
data-privacy-user-ids | "true" | Disables storing user identifiers |
data-privacy-ip-policy | "keep", "stripLastOctet", "remove" | Controls IP address handling |
data-init-only | "true" | Initializes the script without sending a page event |
Verifying the Snippet
After adding the snippet to your app:
- Open browser DevTools -> Network tab
- Look for requests to your tracking host (
/p.js) - In Console:
window.g8should be defined - Call
g8.track('test_event')— you should see a network request
g8 form
Get a progressive form template — an embeddable or popup form that collects data in stages across multiple visits.
Usage:
# Get an embedded form templateg8 form --framework react --variant embedded
# Get a popup form templateg8 form --framework nextjs --variant popup
# Custom field stagesg8 form --framework html --variant embedded \ --stages '[{"stage":1,"fields":[{"name":"email","type":"email","required":true}]}]'
# Output as JSONg8 form --framework vue --variant popup --format jsonOptions:
| Option | Description |
|---|---|
--framework | Target framework (required) |
--variant | Form variant: embedded or popup (required) |
--repo-id | Repository ID for repo-specific config (optional) |
--stages | Custom field stages as JSON string (optional) |
--format | Output format: text (default) or json |
Form Variants:
| Variant | Best for |
|---|---|
embedded | Inline forms within page content (signup sections, footers, sidebars) |
popup | Modal/overlay forms triggered by buttons or page events |
Progressive Form Stages
Forms collect data progressively across visits — asking for a little more each time. The default stages are:
| Stage | Fields | Purpose |
|---|---|---|
| 1 | work_email | Initial capture — lowest friction |
| 2 | first_name, last_name, company | Identity enrichment |
| 3 | job_title, phone | Qualification data |
The form tracks which stage the visitor has completed using localStorage and shows the next stage on their return visit.
Custom stages: Pass a JSON array to --stages to override the defaults:
g8 form --framework react --variant embedded \ --stages '[ {"stage": 1, "fields": [ {"name": "email", "type": "email", "required": true} ]}, {"stage": 2, "fields": [ {"name": "name", "type": "text", "required": true}, {"name": "role", "type": "select", "required": false, "options": ["Developer", "Manager", "Executive"]} ]} ]'Data Flow
When a form is submitted, the data flows through graph8’s tracking pipeline:
- Form captures field values from the visitor
g8.identify()sends the data to graph8’s CDPg8.track()records the form submission event- Data appears in the contact profile in your graph8 workspace
Output Formats
| Format | Flag | Description |
|---|---|---|
| Text | --format text (default) | Human-readable output with headers, code blocks, and setup steps |
| JSON | --format json | Machine-readable output — same structure as the MCP tool response |
The JSON format is useful for piping into other tools or scripts:
g8 snippet --framework html --format json | jq '.snippet_code'Workflow
The recommended order for integrating graph8 into your app:
-
Install the tracking snippet — this is always the first step
Terminal window g8 snippet --framework nextjs -
Add the snippet to your app — follow the setup steps in the output
-
Configure tracking — add identify and track calls:
// On login/signupg8.identify("user-123", { email: "user@example.com", name: "Jane" });// On key actionsg8.track("plan_selected", { plan: "pro", billing: "annual" }); -
Add progressive forms — once tracking is working:
Terminal window g8 form --framework nextjs --variant embedded -
Verify - open DevTools Network tab and look for requests to your tracking host
CRM Commands
g8 search-contacts
Search contacts already in your CRM.
g8 search-contacts --job-title "VP Sales" --limit 10g8 search-contacts --email john@acme.comg8 search-contacts --company "Acme" --seniority VPg8 search-contacts --list-id 637| Option | Description |
|---|---|
--email | Filter by email (exact match) |
--name | Filter by name (partial match) |
--job-title | Filter by job title (partial match) |
--seniority | Filter by seniority (C-Suite, VP, Director, Manager) |
--company | Filter by company name (partial match) |
--country | Filter by country |
--list-id | Filter by contact list ID |
--page | Page number (default 1) |
--limit | Results per page (default 25) |
g8 search-companies
Search companies in your CRM.
g8 search-companies --industry "SaaS" --limit 10g8 search-companies --domain acme.com| Option | Description |
|---|---|
--domain | Filter by domain |
--industry | Filter by industry |
--name | Filter by company name |
--page | Page number (default 1) |
--limit | Results per page (default 25) |
g8 create-contact
Create a new contact in your CRM.
g8 create-contact --email jane@acme.com --first-name Jane --last-name Smith --job-title "VP Sales"g8 create-contact --email john@startup.io --list-id 637| Option | Description |
|---|---|
--email | Work email (required) |
--first-name | First name |
--last-name | Last name |
--job-title | Job title |
--company-domain | Company domain |
--list-id | Add to this list immediately |
g8 create-list
Create a new contact or company list.
g8 create-list --title "VP Sales - SaaS SMB"g8 create-list --title "Target Companies" --type companies| Option | Description |
|---|---|
--title | List name (required) |
--type | contacts (default) or companies |
g8 add-to-list
Add existing contacts to a list.
g8 add-to-list --list-id 637 --contact-ids 5028106,5028105,5028104| Option | Description |
|---|---|
--list-id | List ID (required) |
--contact-ids | Comma-separated contact IDs (required) |
Prospecting Commands
g8 lookup-person
Look up a single person in graph8’s 300M+ data index. Costs 1 credit.
g8 lookup-person --email mark.rubin@tiledb.comg8 lookup-person --linkedin "linkedin.com/in/jane-smith"g8 lookup-person --first-name Jane --last-name Smith --company-domain acme.com| Option | Description |
|---|---|
--email | Email address |
--linkedin | LinkedIn URL |
--first-name | First name (use with last-name + company-domain) |
--last-name | Last name |
--company-domain | Company domain |
g8 lookup-company
Look up a company. Costs 1 credit.
g8 lookup-company --domain tiledb.comg8 lookup-company --name "Acme Corp"g8 find-contacts
Search the open data index for new prospects. Credits charged per result.
g8 find-contacts --filters '[{"field":"seniority_level","operator":"any_of","value":["VP","Director"]},{"field":"company_industry","operator":"contains","value":["SaaS"]}]' --limit 10| Option | Description |
|---|---|
--filters | JSON array of filter objects (required) |
--page | Page number (default 1) |
--limit | Results per page (default 25) |
Filter fields: first_name, last_name, work_email, job_title, seniority_level, company_name, company_domain, company_industry, company_employee_count, company_revenue, country, state, city
Operators: any_of, contains, all_of, none_of, is_empty, is_not_empty, between, exists
g8 find-companies
Search the company database. Credits charged per result.
g8 find-companies --filters '[{"field":"industry","operator":"contains","value":["SaaS"]},{"field":"employee_count","operator":"between","value":[50,500]}]'g8 build-list
Search for prospects and save to a new list. Credits charged per contact saved.
g8 build-list --filters '[{"field":"seniority_level","operator":"any_of","value":["VP"]}]' --title "VP Sales - SaaS" --max-results 50| Option | Description |
|---|---|
--filters | JSON filter array (required) |
--title | List name (required) |
--max-results | Max contacts to save (default 100) |
Enrichment
g8 enrich
Enrich contacts with verified emails, phones, and company data. Credits charged per contact.
g8 enrich --contact-ids 5028106,5028105,5028104 --list-id 637| Option | Description |
|---|---|
--contact-ids | Comma-separated contact IDs (required) |
--list-id | List ID the contacts belong to (required) |
Sequences
g8 sequences
List available outbound sequences.
g8 sequences --limit 10g8 add-to-sequence
Enroll contacts in an outbound sequence.
g8 add-to-sequence --sequence-id "0686895f-..." --contact-ids 5028106,5028105 --list-id 637| Option | Description |
|---|---|
--sequence-id | Sequence ID from g8 sequences (required) |
--contact-ids | Comma-separated contact IDs (required) |
--list-id | List ID (required) |
g8 create-sequence
Create a new outreach sequence.
g8 create-sequence --name "Q2 VP Outbound" --description "Multi-step email + LinkedIn sequence"| Option | Description |
|---|---|
--name | Sequence name (required) |
--description | Sequence description |
--steps | JSON array of step configs |
--channels | JSON array of channel configs |
--campaign-id | Link to a campaign (optional) |
g8 sequence-preview
Preview a sequence’s steps and channels before launching.
g8 sequence-preview --sequence-id "0686895f-..."g8 update-sequence
Update sequence metadata.
g8 update-sequence --sequence-id "0686895f-..." --name "Updated Name" --description "New goal"g8 pause-sequence
Pause a live sequence. No new messages will be sent until resumed.
g8 pause-sequence --sequence-id "0686895f-..."g8 resume-sequence
Resume a paused sequence. Execution times are recalculated respecting business hours.
g8 resume-sequence --sequence-id "0686895f-..."g8 sequence-analytics
Get performance metrics for a sequence.
g8 sequence-analytics --sequence-id "0686895f-..."Returns overview (total contacts, completion rate), performance (funnel, response rates), engagement (reply rate, bounce rate), and timeline data.
g8 delete-sequence
Archive a sequence (soft delete). Active sequences are paused first.
g8 delete-sequence --sequence-id "0686895f-..."Inbox
g8 inbox-list
List reply threads across email, SMS, and LinkedIn.
g8 inbox-list --channel email --limit 20g8 inbox-list --sequence-id "0686895f-..." --status unreadg8 inbox-list --assignee jane@company.com --tag qualified| Option | Description |
|---|---|
--channel | Filter by channel: email, sms, linkedin |
--sequence-id | Filter by sequence |
--status | Filter by thread status |
--assignee | Filter by assigned user email |
--tag | Filter by tag |
--page | Page number (default 1) |
--limit | Results per page (default 20) |
g8 inbox-get
Get a single reply thread with full message history.
g8 inbox-get --reply-id <thread-id> --channel emailg8 inbox-assign
Assign a reply thread to a team member.
g8 inbox-assign --reply-id <thread-id> --assignee jane@company.comg8 inbox-tag
Tag a reply thread for categorization.
g8 inbox-tag --reply-id <thread-id> --tag-ids "qualified,hot-lead"g8 inbox-draft
Generate an AI reply draft based on conversation context. Charges credits.
g8 inbox-draft --reply-id <thread-id>g8 inbox-send
Send a reply via email, SMS, or LinkedIn.
g8 inbox-send --reply-id <thread-id> --channel email --body "Thanks for your interest..."Audience & CRM Sync
g8 sync-audience-list
List configured audience syncs to ad platforms.
g8 sync-audience-listg8 sync-audience-create
Create a new audience sync to Meta, LinkedIn Ads, Google Ads, or X.
g8 sync-audience-create --audience-id 42 --platform meta --mode mirror --cadence 24| Option | Description |
|---|---|
--audience-id | Source audience/list ID (required) |
--platform | Target platform: meta, linkedin, google, x (required) |
--mode | Sync mode: mirror (full replace) or append_only (required) |
--cadence | Refresh cadence in hours (0 = manual only) |
g8 sync-audience-trigger
Manually trigger a sync run.
g8 sync-audience-trigger --config-id <id>g8 sync-audience-runs
View sync run history with record counts.
g8 sync-audience-runs --config-id <id>g8 sync-audience-errors
View error logs for failed sync runs.
g8 sync-audience-errors --config-id <id>g8 sync-crm-list
List connected CRM integrations.
g8 sync-crm-listg8 sync-crm-push
Push contacts, companies, or list memberships to a CRM.
g8 sync-crm-push --provider hubspot --type contacts --records '[{"email":"jane@acme.com","properties":{"firstname":"Jane"}}]'g8 sync-crm-push --provider salesforce --type companies --records '[{"Name":"Acme Corp","Website":"acme.com"}]'| Option | Description |
|---|---|
--provider | CRM provider: hubspot, salesforce, pipedrive, zoho, sugarcrm (required) |
--type | Push type: contacts, companies, lists (required) |
--records | JSON array of records to push (required) |
g8 sync-crm-fields
Discover available field mappings for a CRM provider.
g8 sync-crm-fields --provider hubspotg8 sync-crm-status
Check CRM connection health and rate limits.
g8 sync-crm-status --provider salesforceCampaigns
g8 campaigns
List campaigns in your organization.
g8 campaigns --limit 10g8 campaign
Get full details for a specific campaign.
g8 campaign 4781adce-464b-402e-9a69-b6dbb6376150Piping & Scripting
All commands output JSON, making them scriptable:
# Extract emails from search resultsg8 search-contacts --job-title "CTO" --limit 50 | jq '.[].work_email'
# Count contacts in a listg8 search-contacts --list-id 637 | jq 'length'
# Export to CSVg8 search-contacts --seniority VP --limit 100 | jq -r '.[] | [.first_name,.last_name,.work_email,.job_title] | @csv'