| name | soku-cli-integration |
| description | Install and use Soku CLI to give AI agents secure command-line access to marketing data, ad platforms, GA4, PostHog, and growth automation. |
| triggers | ["install soku cli","query google ads data","access ga4 analytics","automate marketing tasks","publish seo content with soku","manage ad campaigns through soku","connect to posthog with soku","use soku for growth stack"] |
Soku CLI Integration
Skill by ara.so — Devtools Skills collection.
Overview
Soku CLI is a command-line interface that provides secure, typed access to your entire growth stack—Google Ads, Meta Ads, GA4, PostHog, SEO hosting, and more—without exposing API keys in prompts or requiring MCP hosts. Commands are self-documenting and return stable JSON envelopes that AI agents can parse reliably. All delivery-changing writes (like creating campaigns) go through a human review gate.
Key capabilities:
- Query normalized reporting across ad platforms (Google, Meta, TikTok, ChatGPT Ads)
- Access GA4 and PostHog analytics
- Create and manage ad campaigns with human approval
- Publish SEO content
- Schedule recurring automations
- Manage workspace context files
Installation
Prerequisites
- Node.js 20 or newer
- npm or npx
Global installation
npm install -g @soku-ai/cli
Without global install
npx @soku-ai/cli --help
Verify installation
soku --version
Authentication & Workspace Setup
Sign in with browser-based device flow
soku auth login
This opens a browser for OAuth authentication. The CLI stores credentials securely (using keytar when available, or encrypted file storage as fallback).
Check authentication status
soku auth status
Find and select a workspace
soku workspace resolve <brand-name>
soku workspace use-brand <brand-name>
soku workspace status
Sign out
soku auth logout
Core Command Structure
All commands follow a consistent pattern:
soku <namespace> <action> [options]
Namespaces:
auth - Authentication management
workspace - Organization/brand context
ads - Advertising platforms
ga4 - Google Analytics 4
posthog - PostHog analytics
seo-hosting - SEO page management
automation - Scheduled tasks
context - Context Hub file management
egress - Third-party API calls
review - Human approval workflow
skill - Agent skill management
Get help for any command
soku --help
soku ads --help
soku ads query-single-dimension --help
Working with Advertising Data
List ad accounts
soku ads list-ad-accounts --platform google
soku ads list-ad-accounts --platform meta
soku ads list-ad-accounts
Query single-dimension reports
soku ads query-single-dimension \
--platform google \
--account-id 123-456-7890 \
--dimension campaign \
--date-start 2026-06-01 \
--date-end 2026-06-30
Available dimensions: campaign, ad_group, ad, keyword
Query two-dimension reports
soku ads query-two-dimension \
--platform google \
--account-id 123-456-7890 \
--dimension-one campaign \
--dimension-two ad_group \
--date-start 2026-06-01 \
--date-end 2026-06-30
Google Ads GAQL queries
For custom breakdowns beyond standard dimensions:
soku ads google gaql \
--account-id 123-456-7890 \
--query "SELECT campaign.name, metrics.impressions, metrics.clicks FROM campaign WHERE segments.date DURING LAST_30_DAYS"
Create a Meta campaign (with review)
soku ads meta campaign create \
--account-id act_123456789 \
--name "Q3 Product Launch" \
--objective OUTCOME_TRAFFIC \
--summary "Create paused Meta traffic campaign for Q3 launch"
This returns a review ID instead of executing immediately:
{
"ok": true,
"data": {
"review_id": "rev_abc123",
"status": "pending"
}
}
Review and approve changes
soku review show rev_abc123
soku review approve rev_abc123
soku review reject rev_abc123 --reason "Budget needs adjustment"
soku review list --status pending
Analytics Integration
Google Analytics 4
soku ga4 list-properties
soku ga4 get-property-overview --property-id 123456789
soku ga4 list-traffic-sources \
--property-id 123456789 \
--start-date 2026-06-01 \
--end-date 2026-06-30
soku ga4 list-conversion-events --property-id 123456789
PostHog
soku posthog list-projects
soku posthog query \
--project-id 12345 \
--tool execute-sql \
--arguments '{"query":"SELECT event, count() as count FROM events WHERE timestamp >= now() - INTERVAL 7 DAY GROUP BY event ORDER BY count DESC LIMIT 10"}'
soku posthog query \
--project-id 12345 \
--tool get-insights \
--arguments '{"filters":{"date_from":"-7d"}}'
SEO Hosting
Create and publish a page
soku seo-hosting pages put \
--section blog \
--slug product-launch-2026 \
--title "Product Launch Notes" \
--html-file ./content/launch.html
soku seo-hosting pages publish \
--section blog \
--slug product-launch-2026
soku seo-hosting pages list --section blog
soku seo-hosting pages get \
--section blog \
--slug product-launch-2026
Manage domains
soku seo-hosting domains list
soku seo-hosting domains add \
--domain blog.example.com \
--section blog
Automations
Create scheduled tasks
soku automation create \
--name "Weekly ad account health check" \
--prompt "Review all active ad accounts, identify campaigns with declining performance, and flag anomalies for human review" \
--cron "0 9 * * 1" \
--timezone America/Los_Angeles
soku automation create \
--name "Daily budget utilization" \
--prompt "Check yesterday's spend across all platforms and alert if any account spent >110% or <70% of daily budget" \
--cron "0 8 * * *" \
--timezone America/New_York
Manage automations
soku automation list
soku automation get --id auto_abc123
soku automation pause --id auto_abc123
soku automation resume --id auto_abc123
soku automation delete --id auto_abc123
Context Hub
Manage files that agents can use as context:
soku context upload ./campaign-brief.pdf --dir research
soku context upload ./docs/*.md --dir documentation
soku context list
soku context list --dir research
soku context download campaign-brief.pdf --output ./local-copy.pdf
soku context delete campaign-brief.pdf --dir research
Agent Skills
Install workflow skills to give agents structured knowledge:
soku skill install --all --global
soku skill install soku-ads-reporting --global
soku skill list
soku skill status
soku skill update --all
The meta skill is available at skills/soku/SKILL.md in the installation directory.
JSON Output & Parsing
In non-interactive environments, all commands return structured JSON:
Success response
{
"ok": true,
"data": {
"accounts": [
{
"id": "123-456-7890",
"name": "Main Account",
"platform": "google"
}
]
}
}
Error response
{
"ok": false,
"error": {
"code": "UNAUTHORIZED",
"message": "Session expired. Run 'soku auth login'"
}
}
Parsing in scripts (TypeScript)
import { exec } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);
async function getAdAccounts(platform: string) {
try {
const { stdout } = await execAsync(
`soku ads list-ad-accounts --platform ${platform}`
);
const response = JSON.parse(stdout);
if (!response.ok) {
throw new Error(response.error.message);
}
return response.data.accounts;
} catch (error) {
console.error('Failed to fetch ad accounts:', error);
throw error;
}
}
const accounts = await getAdAccounts('google');
console.log(`Found ${accounts.length} accounts`);
Parsing in scripts (Shell)
#!/bin/bash
ACCOUNTS=$(soku ads list-ad-accounts --platform google)
if [ "$(echo "$ACCOUNTS" | jq -r '.ok')" = "true" ]; then
echo "$ACCOUNTS" | jq -r '.data.accounts[].id' | while read -r account_id; do
echo "Processing account: $account_id"
soku ads query-single-dimension \
--platform google \
--account-id "$account_id" \
--dimension campaign \
--date-start "2026-06-01" \
--date-end "2026-06-30"
done
else
echo "Error: $(echo "$ACCOUNTS" | jq -r '.error.message')"
exit 1
fi
Direct Capability Calls
If a capability doesn't have a typed command yet, use soku call:
soku call --help
soku call ads list_ad_accounts -p platform=google
soku call ads query_single_dimension \
-p platform=google \
-p account_id=123-456-7890 \
-p dimension=campaign \
-p date_start=2026-06-01 \
-p date_end=2026-06-30
soku call ads list_ad_accounts --help
Common Workflows
Weekly performance report
async function generateWeeklyReport() {
const googleAccounts = await execSoku('ads list-ad-accounts --platform google');
const metaAccounts = await execSoku('ads list-ad-accounts --platform meta');
const reports = [];
for (const account of [...googleAccounts, ...metaAccounts]) {
const data = await execSoku(`ads query-single-dimension \
--platform ${account.platform} \
--account-id ${account.id} \
--dimension campaign \
--date-start ${sevenDaysAgo()} \
--date-end ${today()}`);
reports.push({ account: account.name, data });
}
return formatReport(reports);
}
Campaign launch checklist
async function launchCampaign(config: CampaignConfig) {
const createResult = await execSoku(`ads meta campaign create \
--account-id ${config.accountId} \
--name "${config.name}" \
--objective ${config.objective} \
--summary "${config.summary}"`);
const reviewId = createResult.data.review_id;
console.log('Campaign ready for review:');
const review = await execSoku(`review show ${reviewId}`);
console.log(JSON.stringify(review.data, null, 2));
const approved = await askHumanForApproval();
if (approved) {
await execSoku(`review approve ${reviewId}`);
console.log('Campaign launched!');
} else {
await ();
}
}
Cross-platform performance comparison
async function compareAdPlatforms(startDate: string, endDate: string) {
const platforms = ['google', 'meta', 'tiktok'];
const results = {};
for (const platform of platforms) {
const accounts = await execSoku(`ads list-ad-accounts --platform ${platform}`);
let totalSpend = 0;
let totalConversions = 0;
for (const account of accounts.data.accounts) {
const metrics = await execSoku(`ads query-single-dimension \
--platform ${platform} \
--account-id ${account.id} \
--dimension campaign \
--date-start ${startDate} \
--date-end ${endDate}`);
totalSpend += sumMetric(metrics.data, 'spend');
totalConversions += sumMetric(metrics.data, 'conversions');
}
results[platform] = {
spend: totalSpend,
conversions: totalConversions,
cpa: totalSpend / totalConversions
};
}
results;
}
Troubleshooting
Authentication issues
Problem: Session expired or UNAUTHORIZED errors
soku auth logout
soku auth login
soku auth status
Problem: Browser doesn't open during login
Workspace context issues
Problem: No workspace selected
soku workspace status
soku workspace list
soku workspace use-brand <brand-name>
Command not found
Problem: Typed command doesn't exist yet for new capability
soku call <namespace> <action> --help
soku call <namespace> <action> -p key=value
Review workflow issues
Problem: Review ID returned but want to skip review (for testing)
soku review approve <review_id>
JSON parsing issues
Problem: Malformed JSON output
soku ads list-ad-accounts 2>/dev/null
Permission issues
Problem: FORBIDDEN or missing capabilities
soku workspace status
soku workspace use-brand <correct-brand>
Rate limiting
Problem: RATE_LIMIT_EXCEEDED errors
sleep 1
Environment Variables
Soku CLI respects standard environment variables:
NODE_ENV - Set to production to suppress dev warnings
CI - Set to true to force non-interactive mode
NO_COLOR - Set to disable colored output
SOKU_API_URL - Override API endpoint (advanced use)
Best Practices for AI Agents
- Always check authentication first: Run
soku auth status before executing workflows
- Parse JSON reliably: Check
response.ok before accessing response.data
- Use typed commands when available: They provide better validation than raw
soku call
- Handle reviews properly: Never assume auto-approval; present reviews to humans
- Cache workspace context: Don't repeatedly call
soku workspace status
- Batch queries efficiently: Minimize API calls by requesting broader date ranges
- Install skills globally: Run
soku skill install --all --global during setup
- Provide context in summaries: The
--summary flag for writes should explain WHY
Development & Testing
When developing scripts that use Soku CLI:
import { exec } from 'node:child_process';
async function checkSokuCLI() {
try {
await execAsync('soku --version');
return true;
} catch {
console.error('Soku CLI not found. Install: npm install -g @soku-ai/cli');
return false;
}
}
async function testCampaignCreate(config: any) {
const result = await execSoku(`ads meta campaign create \
--account-id ${config.accountId} \
--name "TEST ${config.name}" \
--objective ${config.objective} \
--summary "Test campaign - do not approve"`);
const reviewId = result.data.review_id;
console.log(`Test review created: ${reviewId}`);
console.log('Remember to reject this review');
return reviewId;
}
Further Resources