GEOly CLI: Use GEOly from Your Own Agent
Install the GEOly CLI, authorize once, and your coding agent — Claude Code, Codex, Cursor, or any agent that can run shell commands — can query your brand's AI visibility data directly. The credential stays on your machine and usage draws on your organization's own credits.
The GEOly CLI (geoly) lets the agent you already work with ask GEOly for your brand's AI visibility data. Install it, authorize once, and Claude Code, Codex, Cursor, OpenCode, or an agent you built yourself can run geoly commands to read visibility, prompts, AI answers, citations, competitors, audits, and public industry data. The credential stays on your machine — the agent never sees a key — and usage draws on your organization's own credits.
Paste this into your agent
The fastest way to start: copy this prompt into Claude Code, Codex, Cursor, or any agent that can run commands. It installs the CLI, signs you in, and answers your first question.
What it looks like
You ask your coding agent a question in plain language:
You: How did our ChatGPT visibility change over the last 7 days, and which prompts moved most?
The agent recognizes a GEOly question and runs a command in your terminal:
geoly run "How did our ChatGPT visibility change over the last 7 days, and which prompts moved most?"
GEOly's hosted GEO agent picks the right data tools, reads your monitoring data, and returns one receipt on stdout (progress goes to stderr):
{
"run_id": "run_…",
"status": "done",
"answer": "## ChatGPT visibility, last 7 days\n…",
"stopped": "done",
"stopped_reason": "done",
"steps": 4,
"tools_used": ["get_brand_context", "get_brand_overview", "get_prompt_list"],
"credits_cost": 54,
"credits_remaining": 9946,
"saved_to": ".geoly/runs/run_….json"
}
Your agent reads answer, cites the numbers, and carries on with your task. When it needs exact fields instead of a written answer — to build a table, loop over prompts, or check a single number — it calls one data tool directly:
geoly call get_brand_overview --time_range 7d --platform chatgpt
Get started in three steps
Step 1 — Install
macOS / Linux
curl -fsSL https://geoly.ai/install.sh | sh
Windows (PowerShell)
irm https://geoly.ai/install.ps1 | iex
The installer downloads one self-contained binary (no Node.js, no Python, no sudo) and verifies its SHA-256 against the release manifest. On macOS and Linux it installs to ~/.local/bin and prints the exact line to add if that directory is not on your PATH. On Windows it installs to %LOCALAPPDATA%\Programs\geoly and adds it to your user PATH. Supported: macOS (Apple silicon and Intel), Linux (x64, arm64), Windows (x64).
geoly --version
Update any time with geoly upgrade. If github.com is slow or blocked on your network, set GEOLY_INSTALL_BASE to an HTTPS mirror on *.geoly.ai; the installers and geoly upgrade both honor it.
Step 2 — Run geoly init
geoly init
geoly init does two things:
- Installs the GEOly Agent Skill into the agent hosts it finds on this machine. It looks for
~/.claude,~/.codex, and~/.cursorand writes the skill to~/.claude/skills/geoly-mcp/,~/.codex/skills/geoly-mcp/, and~/.cursor/skills/geoly-mcp/respectively. The skill is fetched from app.geoly.ai so it matches the live server (a copy embedded in the CLI is used if that is unreachable). It teaches the agent when to usegeoly runversusgeoly call, how to resolve the organization and brand first, and how to read GEOly metrics correctly. It changes no other configuration and grants no permissions. - Signs you in (see Step 3). On a machine without a browser it starts the paste-code sign-in and tells you the command that finishes it.
Variants:
geoly init --agent codex # only one host: claude-code | codex | cursor
geoly init --no-login # install the skill only (dotfiles, CI images)
Add .geoly/ to your project's .gitignore: geoly run writes receipts there.
Step 3 — Authorize once
The CLI signs in with OAuth — the same authorization as GEOly MCP. What the CLI can reach is exactly what you approve on the consent screen.
On your own computer
You do not have to do anything in advance: the first command that needs data starts the sign-in (or run geoly auth login explicitly). The CLI:
- opens your browser on the GEOly authorization page and prints the same URL on stderr in case the browser does not open;
- waits on a local port (
127.0.0.1) for up to 180 seconds; - continues the original command once you approve.
In the browser, sign in to GEOly and complete the consent screen:
- Choose the organization the CLI may use — one organization, or all of your organizations (read-only).
- Approve read access for the resources you need (brands, prompts, citations, analytics, audits, sources, public data…).
- Tick Write only for resources you want your agent to change, and only with a single organization.
The terminal then shows geoly: authorized ✓. If several commands start at once (agents often run commands in parallel), they share one browser sign-in.
geoly auth login
{
"authorized": true,
"profile": "default",
"expiresAt": "2026-10-07T09:30:00.000Z",
"scope": "openid profile"
}
If a browser exists but should not be launched automatically (WSL, for example), use geoly auth login --no-browser: the URL is printed and the CLI still listens locally.
On a machine without a browser (SSH, containers, remote servers)
The CLI switches to a paste-code sign-in when there is no browser to open. It does this automatically when SSH_CONNECTION, SSH_TTY, or SSH_CLIENT is set, when CI is set, or on Linux without DISPLAY / WAYLAND_DISPLAY. --remote forces it.
# 1. Start the sign-in on the remote machine
geoly auth login --remote
Open the printed URL in a browser on any device, sign in, and complete the same consent screen. The page then shows a one-time code.
# 2a. In an interactive terminal the CLI is already waiting:
Paste the code: 7Hk2…
# 2b. Otherwise (for example, when your agent ran step 1 for you):
geoly auth login --code 7Hk2…
Without an interactive terminal, step 1 prints the pending state and exits with code 0:
{
"authorized": false,
"pending": true,
"profile": "default",
"url": "https://app.geoly.ai/…",
"next": "geoly auth login --code <code>"
}
- A pending sign-in stays valid for 10 minutes; later commands reuse it instead of starting another.
- The code is single-use, short-lived, and useless without the verifier kept on the machine that started the sign-in, so it is safe to relay through your agent's chat.
- If an ordinary command needs credentials on such a machine, it prints the URL, stops with exit code 3, and suggests
geoly auth login --code <code>.
Servers and CI
Sign in once on the runner itself with the paste-code flow: run geoly auth login --remote, open the URL in any browser, then run geoly auth login --code <code> on the runner. The credential is stored for that machine's user and reused until it expires (about 14 days); geoly auth status shows when, and after that you sign in the same way again.
Automatic sign-in is turned off when CI is set, when GEOLY_NO_AUTO_AUTH=1 is set, or with --no-auto-auth: a missing or expired credential then fails at once with exit code 3 instead of waiting for a browser, so a job never hangs on a sign-in.
Check, switch, and sign out
geoly auth status # signed in? until when?
geoly whoami # which account, organization, mode, and tools?
geoly auth logout # delete this profile's stored credentials
geoly auth status prints mode, authorized, profile, endpoint, expiresAt, and scope. geoly whoami asks the server and prints the auth mode, the organization in use, token expiry, mode (single, multi-brand, or multi-org), toolCount, whether public industry tools are enabled, and writeTools — the write tools your consent actually granted.
The access token lasts about 14 days; after that the next command signs you in again.
| File | Contents |
|---|---|
~/.geoly/credentials-<profile>.json | OAuth client registration and access token (owner-only permissions on macOS/Linux) |
~/.geoly/settings-<profile>.json | The organization you last picked in an interactive session |
./.geoly/runs/<run_id>.json | Receipts from geoly run, in the current directory |
Organizations and brands. Choosing one organization gives read access plus write for the resources you ticked; choosing all organizations is read-only. The tools you see also depend on your plan and role — a missing tool does not mean sign-in failed.
geoly call list_organizations # when your access spans several organizations
geoly call list_brands # when an organization has several brands
geoly call get_brand_overview --org <org_id> --brand_id <brand_id>
geoly run "…" --org <org_id> --brand <brand_id>
--org <org_id>works on every command and narrows it to one organization.- In the interactive
geolysession, a multi-organization account is asked once, with a searchable list, and the answer is remembered in~/.geoly/settings-<profile>.json. Non-interactive commands never prompt: they fail with the candidates and the flag to add. Pass--orgor delete that file to change it. - Use
--profile <name>on any command to keep a second account side by side, orgeoly auth logoutand sign in again.
Using it in your agent
Claude Code, Codex, and Cursor
After geoly init, the GEOly skill is in each host's skills folder. Start a new session and ask in plain language, for example "Use geoly to check our citation gaps this month". The agent runs geoly in your terminal, reads JSON from stdout, and follows up on its own. If the agent was already open when you ran geoly init, restart it so it picks up the new skill. geoly upgrade refreshes the skill together with the CLI.
Any agent that can run shell commands
OpenCode, a custom agent, a CI job driven by an LLM — anything that can run a command and read its output can use GEOly. Put this in its system prompt or AGENTS.md:
**GEOly (AI visibility data)**
Use the `geoly` CLI for questions about our brand's visibility in AI answers
(ChatGPT, Perplexity, Gemini, Google AI Mode, Google AI Overview, Copilot).
- A whole question that ends in a written answer: `geoly run "<question>"`.
Read `answer` from the JSON on stdout. If `status` is `running`, run the `next`
command it prints (`geoly runs wait <run_id>`); never re-issue the same run.
If `stopped` is `max_steps`, treat the answer as partial (`stopped_reason` says why).
- A specific data pull: discover with `geoly tools --json`, read parameters with
`geoly schema <tool>`, then `geoly call <tool> --<param> <value>`.
Parameter names are used verbatim (underscores); unknown parameters are rejected.
- Start a session with `geoly call get_brand_context` (free) to learn the brand,
plan, platforms, topics, and competitors.
- stdout is JSON data; stderr is progress and errors. Add `--error-format json`
to get errors as JSON.
- Exit codes: 0 ok, 1 tool error, 2 fix the command, 3 sign in (`geoly auth login`),
4 rate limited (wait `retryAfter`), 5 no active plan, 6 service trouble (retry once),
7 credits used up.
- Never pass `--yes` or `--allow-writes` unless the user explicitly asked for a change.
Servers and CI
Sign in once on the runner with geoly auth login --remote, then --code, as described in Step 3, and sign in again when the credential expires. Add --error-format json and branch on exit codes (3 means the runner needs a new sign-in).
What your agent can ask
Tools are grouped below by the question they answer. The complete, current list for your account is always geoly tools --json — the server can add tools without a CLI release — and geoly schema <tool> shows exact parameters. Platform codes are chatgpt, perplexity, gemini, google_ai, copilot, and google_ai_overview.
Orientation
| Tool | Answers |
|---|---|
get_brand_context | Free, once per session: your brand, organization and plan, entitled platforms, topics, tracked competitors, data window, remaining credits. |
list_organizations / list_brands | Which organizations and brands you can reach (shown only for multi-organization or multi-brand access). |
Brand visibility and trends
| Tool | Answers |
|---|---|
get_brand_overview | The Performance page KPIs: visibility, mention rate, share of voice, best and worst platform, per-platform stats. |
query_analytics | Daily trends and custom aggregations by date, platform, topic, or domain — no SQL. |
get_brand_board | Your brand against confirmed competitors, like the Performance brand board, with an optional trend. |
geoly call query_analytics --dataset brand_citations_daily --start_date 2026-09-01 --end_date 2026-09-21 \
--dimensions '["date","platform"]' --metrics '["aigvr","mentionRate","citationRate"]'
Prompts and AI answer text
| Tool | Answers |
|---|---|
get_prompt_list | Monitored prompts with visibility, mention rate, and citation rate, filtered and sorted like the Prompts table. |
get_prompt_detail | One prompt over a window: ranking, competitors, trend, cited domains. |
list_brand_answers | Every AI answer for the brand in a window, newest first. |
get_prompt_record_detail | One answer in full: text, citations, the searches the AI ran, brands named. |
geoly call list_brand_answers --time_range 7d --platform perplexity --only_mentioned --page_size 20
Citations and sources
| Tool | Answers |
|---|---|
get_citation_overview | Which domains AI answers cite, your share, and the biggest movers. |
list_citation_domains | The cited-domain table, including the gaps-only view (a competitor is mentioned, you are not). |
get_domain_detail / get_page_detail | One domain's or one URL's citation profile. |
geoly call list_citation_domains --time_range 30d --gap_only --page_size 20
Competitors and the brand library
| Tool | Answers |
|---|---|
get_competitor_list | Your brand library: tracked, suggested, and removed brands, with 30-day mentions. |
get_platform_matrix | Brand and competitors × platform: visibility, share of mentions, or citation. |
get_competitor_cooccurrence | Answers where you and other brands appear together. |
geoly call get_competitor_list --status tracked
AI verdict and sentiment
| Tool | Answers |
|---|---|
get_competitor_polarity | Which competitors AI answers prefer over you — the AI Verdict board. |
get_risk_context_sources | Sources cited in answers that judge your brand, with the share of negative judgments. |
get_brand_mention_samples | Recent answers that mention you, with the surrounding text. |
get_sentiment_dashboard | Answer-level sentiment distribution and trend. |
geoly call get_competitor_polarity --time_range 30d
AI search queries
| Tool | Answers |
|---|---|
get_brand_search_queries | The web searches ChatGPT and Perplexity ran while answering your prompts: overview, grouped evidence, one query, or one prompt's queries. |
geoly call get_brand_search_queries --mode overview --time_range 30d --platform chatgpt
Traffic: GA4 and Cloudflare
| Tool | Answers |
|---|---|
get_ga4_traffic_data | AI-referred sessions next to whole-site traffic from GA4; page-level data with page_path. |
get_cf_traffic_data | AI crawler requests to your site from Cloudflare, including blocked crawlers. |
geoly call get_ga4_traffic_data --time_range 30d
Both need the matching integration connected in GEOly; get_brand_context shows which ones are ready.
Site audits and Agent Ready
| Tool | Answers |
|---|---|
get_audit_list / get_audit_detail | Your GEO audit history, and one report with scores, issues, and how to fix them. |
get_audit_pages | Per-page results of a site audit. |
get_agent_ready_scans / get_agent_ready_scan_detail | Your Agent Readiness scans and one scan's full result. |
geoly call get_audit_detail --audit_id <audit_id>
Public industry intelligence
Cross-brand data on categories, topics, brands, shopping shelves, and citation sources. Most of it needs the Grow plan or above plus Public data read permission; the public source tools need Source read permission.
| Tool | Answers |
|---|---|
search_public_entities | Resolve a brand, category, topic, or domain name to public IDs. |
get_public_category / get_public_topic_brand_leaderboard | Who leads a category or topic in AI answers. |
compare_public_brands | Two to four brands side by side on one facet. |
list_public_shopping_boards | Which products AI recommends most across categories. |
get_public_sources_overview / get_public_source_domain_detail | The most-cited source domains, and one domain's profile. |
geoly call search_public_entities --query "standing desk" --limit 10
Questions to paste into your agent
Once the CLI is set up, copy any of these into your agent.
More ideas: "Use geoly to read our latest site audit and turn the critical issues into a fix list." · "With geoly, compare our brand with two competitors in our category's public data."
geoly run or geoly call?
geoly run "<question>" | geoly call <tool> --<param> <value> | |
|---|---|---|
| What happens | GEOly's hosted GEO agent picks the tools, reads the data, and writes the answer. | Exactly one data tool runs and returns JSON. |
| You get | A receipt: answer, tools used, steps, credits spent. | The tool's raw result. |
| Use it for | Anything that ends in a narrative: a weekly review, a comparison, a "why did this move" investigation. | Exact fields for your own analysis, tables, loops, and exports. |
Calling data tools
geoly tools # table: name, access, first line of the description
geoly tools --json # [{ "name", "title", "access" }] for scripts
geoly schema get_brand_overview # description + full input schema
access is read-only, write, or credit-consuming. Retired names that still forward to a newer tool are marked "deprecated": true. The list is cached for 60 seconds (--refresh bypasses it).
Parameter flags use schema names verbatim, underscores included:
geoly call get_brand_overview --time_range 30d --platform chatgpt # scalars
geoly call get_prompt_list --page 1 --page_size 20 --compact # booleans: presence
geoly call compare_public_brands --brand_ids '["<id_a>","<id_b>"]' --country US --language en # arrays: JSON
geoly call get_prompt_list --data '{"page":1,"page_size":20,"sort_by":"visibility","sort_order":"desc"}'
echo '{"time_range":"7d"}' | geoly call get_brand_overview --input -
Individual flags override the same fields in --data / --input. A tool parameter that shares its name with a CLI flag (org, profile, output, timeout, yes…) goes inside --data. Paging parameters pass through as each tool defines them (page / page_size or limit / offset); when the server marks a partial result (_truncated, hasMore, totalPages), the fields stay in the payload and the CLI adds a hint on stderr.
Write tools — create_prompt, create_topic, create_competitor, archive_prompt, update_prompt_tags, move_prompts_to_topic, trigger_prompt — appear only when the consent granted Write on that resource for one organization. They run only after a confirmation: [y/N] in a terminal or --yes in a script; otherwise the result is write_blocked. trigger_prompt also runs monitoring right away and consumes credits.
Asking the hosted agent
| Flag | What it does |
|---|---|
--brand <id> | The brand to run against (needed when the organization has several) |
--context <text> / --context @file | Extra background; @file reads a UTF-8 (or UTF-16 with BOM) text file |
--spec <name> | A fixed-format deliverable defined on the server: geo-weekly-brand-health, geo-content-brief, geo-keyword-research-report, geo-serp-gap |
--max-credits <n> | Hard ceiling for this run, 25–2000 credits |
--allow-writes | Let the agent use the write tools your consent granted; without it the run is read-only |
--wait <sec> / --no-wait | How long to follow the run (default 100 s) / return as soon as it starts |
-o <file> / --no-save | Write the receipt to a chosen file / skip ./.geoly/runs/ |
--output raw | Stream the answer text to stdout instead of JSON |
Reading the receipt:
statusis the field to branch on:doneandfailedare final;runningis not an answer yet.stopped: "max_steps"means the agent did not finish on its own terms.stopped_reasonsays why:budget(the--max-creditsceiling),deadline,max_steps, orsalvaged. The exit code stays 0, and the CLI warns on stderr that the answer is partial.- With
--spec, the receipt also carriesdeliverable, the server's check of the report against the spec.
Output and exit codes
Flags, output behavior, and exit codes are the stable contract. Tool names and schemas come from the server; discover them rather than hard-coding them.
- stdout is data: JSON, pretty in a terminal and compact when piped.
--output rawprints the raw text (forgeoly run, the answer). - stderr is status: progress, warnings, errors.
-qsilences status lines. --error-format jsonprints each error as one JSON object on stderr:kind,message, and when availablestatus,tool,retryAfter,hint,next(the exact command that moves things forward).kindis one ofauth_expired,grant_missing,rate_limited,subscription_required,quota_exhausted,upstream_unavailable,tool_error,usage_error,write_blocked.- Help is plain text when piped (
geoly --help | cat), so agents can read it. --timeout <sec>(default 30, maximum 120) bounds each request; forgeoly runit bounds the wait for the server to respond, while--waitcontrols how long to follow the run.
| Code | Meaning | What to do |
|---|---|---|
| 0 | Success (a running hand-off from geoly run is also 0) | — |
| 1 | Tool or run error: the server answered, the operation failed | Read the error; usually do not retry |
| 2 | Usage error: bad flag, unknown tool or parameter, rejected arguments; nothing ran | Fix the command; check geoly schema <tool> |
| 3 | Authentication: no valid credential, or the grant does not cover this | geoly auth login |
| 4 | Rate limited | Wait retryAfter seconds, then retry |
| 5 | Subscription required: the organization has no active plan | Needs a person; do not retry |
| 6 | Upstream unavailable: network or service trouble | Short back-off, then retry once |
| 7 | This period's credits are used up | Do not retry; wait for the reset or raise the limit |
Long runs and safe retries
If a run is still going after --wait seconds, geoly run exits 0 with:
{ "status": "running", "run_id": "run_…", "elapsed_s": 100, "next": "geoly runs wait run_…" }
The run continues on the server; a disconnect or Ctrl-C never cancels it.
geoly runs wait run_… # poll every 3 s (change with --interval) for up to --wait seconds
geoly run run_… # print a run's current state
geoly runs list # recent runs for the organization (--limit 1–50, default 20)
Retries never pay twice. Each geoly run sends an idempotency key derived from the organization, brand, spec, question, context, --max-credits, and --allow-writes. Repeating the exact same command within 10 minutes replays the existing run (stderr says replayed run …) instead of starting and charging a new one; changing any of those inputs starts a new run. Scripts can set their own key with --idempotency-key (8–128 characters of A-Z a-z 0-9 _ - : .).
Receipts on disk. Every finished run is written to ./.geoly/runs/<run_id>.json in the current directory, so your agent can read a long answer from the file instead of asking again. -o <file> picks the path (stdout then prints only status, run_id, saved_to).
Credits
GEOly CLI usage draws on your organization's own credits.
- See the balance:
geoly credits(or Settings → Billing in GEOly) returns each organization you can reach with its plan, remaining credits, and reset date.geoly credits --output rawprints the same as plain text, two lines per organization (MCP creditsandAI credits). - Cap a run:
geoly run … --max-credits <n>. The receipt'scredits_costnever exceeds it;credits_remainingshows what is left. - When credits run out, commands that need them exit with code 7 and the hint gives the reset date. Plan allowances are on the pricing page.
Troubleshooting
The browser did not open. Open the URL printed on stderr. On a machine without a browser, use geoly auth login --remote, then geoly auth login --code <code>.
auth_expired / exit 3 in CI. Automatic sign-in is off when CI is set. Sign in once on that machine with geoly auth login --remote, then --code; repeat when the credential expires.
grant_missing. The consent did not cover this. For a write tool, Write was not ticked for that resource, or you chose all organizations: run geoly auth login again and pick one organization with the Write permission you need. If the organization is no longer available, re-authorize and pick again.
--x is not a parameter of <tool> / Unknown argument(s) … Accepted: …. The tool does not have that parameter; nothing was run or billed. The CLI checks your flags before sending:
error[usage_error]: --time-range is not a parameter of get_brand_overview
hint: Did you mean --time_range? Declared parameters: --time_range, --start_date, …
The server applies the same rule to every call and names the accepted arguments, for example Unknown argument(s) nope for get_prompt_list. Accepted: …. org_id and brand_id are accepted everywhere. Use the name from the message, or geoly schema <tool>; names use underscores.
Unknown tool "…". Not available to this account, plan, or grant, or misspelled — the hint suggests the closest names. Try geoly tools --refresh.
"spans multiple organizations" or a brand is required. Add --org <org_id> and, for brand tools, --brand_id <id> (--brand <id> for geoly run). geoly call list_organizations / list_brands show the options.
subscription_required (exit 5) vs quota_exhausted (exit 7). Both are HTTP 402: the first means no active plan, the second means this period's credits are used up. The hint links to billing and shows the reset date.
rate_limited (exit 4). Wait retryAfter seconds and retry.
status: "running". Not an error — run the printed next command.
The answer looks cut short. Check stopped / stopped_reason. budget means the --max-credits ceiling was hit; raise it and ask again.
SPEC_NOT_FOUND. The --spec name is unknown; the error lists the available names.
Limits and boundaries
- Scope is what you approved. The CLI reaches only the organizations and resources granted on the consent screen; choosing all organizations makes everything read-only.
- Read-only by default. Write tools need a Write grant on a single organization plus a confirmation on every call (
[y/N]or--yes);geoly runneeds--allow-writes.trigger_promptis never available to the hosted agent. - Plans. Hosted agent runs need an active subscription; public industry intelligence needs the Grow plan or above and Public data read permission.
- Tool names and schemas evolve. Discover them with
geoly tools --json; do not hard-code a list. - Size limits. A
geoly runquestion can be up to 4,000 characters and--contextup to 16,000. - Runs are bounded. One run spends at most 2,000 credits and has a server-side time limit; an early stop is reported in
stopped_reason. - Local stays local. Credentials, interactive session transcripts (
~/.geoly/sessions/), and receipts are stored only on your machine.
Related
- GEOly MCP User Guide — connect GEOly to Claude, Cursor, VS Code, Windsurf, or Codex without installing a CLI. Same tools, same authorization.
- GEOly Agent API — the HTTP endpoint behind
geoly run, for your own integrations. - GEOly CLI on GitHub — releases and the full command contract.
GEOLY Docs