{"id":51398898,"url":"https://github.com/awkoy/gsc-cli","last_synced_at":"2026-07-04T04:40:29.740Z","repository":{"id":351060101,"uuid":"1209374716","full_name":"awkoy/gsc-cli","owner":"awkoy","description":"LLM-friendly TypeScript CLI and SDK for the Google Search Console API","archived":false,"fork":false,"pushed_at":"2026-04-13T12:10:51.000Z","size":100,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-04T04:40:05.655Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/awkoy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-13T11:13:32.000Z","updated_at":"2026-04-13T12:10:12.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/awkoy/gsc-cli","commit_stats":null,"previous_names":["awkoy/gsc-cli"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/awkoy/gsc-cli","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awkoy%2Fgsc-cli","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awkoy%2Fgsc-cli/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awkoy%2Fgsc-cli/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awkoy%2Fgsc-cli/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/awkoy","download_url":"https://codeload.github.com/awkoy/gsc-cli/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/awkoy%2Fgsc-cli/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35110270,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-04T04:40:29.248Z","updated_at":"2026-07-04T04:40:29.733Z","avatar_url":"https://github.com/awkoy.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# gsc-cli\n\nA LLM-friendly TypeScript CLI and SDK for the Google Search Console API.\n\n`gsc` is built with two consumers in mind: humans who want a fast terminal workflow for managing sites, sitemaps, search analytics, and URL inspection — and AI agents that need predictable, structured output they can parse without guessing. Every command emits a uniform JSON envelope with `ok`, `data`, `error`, and `meta` fields, so a coding agent can pipe `gsc` into its own tools without screen-scraping help text.\n\n\u003e **Status**: pre-1.0. The command surface is stable enough to use day-to-day, but expect minor breaking changes until `v1.0.0`.\n\n## Highlights\n\n- **One-command auth** — `gsc auth login` walks through OAuth, picks (or auto-enables) a GCP project, and persists the quota project. No `gcloud` knowledge required beyond having it installed.\n- **Structured output everywhere** — every command returns `{ ok, data, error, meta }`. Agents and shell scripts can parse it with `jq` and never see surprise prose on stdout.\n- **Three formats** — `json` (default, machine-friendly), `text` (human-friendly), `table` (terminal-friendly). Switch per-command with `--format` or set a default with `gsc config set defaultFormat`.\n- **Sitemap-aware bulk inspect** — `gsc inspect --sitemap` fetches your sitemap, expands index files, and inspects every URL in parallel with rate-limit-aware concurrency.\n- **Filter language for analytics** — `gsc analytics query --filter 'page~/blog/,country=USA'` parses to typed filters with operators `=`, `!=`, `~`, `!~`, `=~`, `!=~`.\n- **Reusable SDK** — the underlying `@gsc-cli/sdk` is a typed HTTP client with retry, rate-limiting, and caching built in. Use it directly from Node.\n- **No-magic auth fallback** — set `GOOGLE_APPLICATION_CREDENTIALS` to a service account JSON and skip OAuth entirely. Works for CI and headless servers.\n\n## Install\n\n```bash\nnpm install -g @gsc-cli/cli\n# or\npnpm add -g @gsc-cli/cli\n# or\nbun add -g @gsc-cli/cli\n```\n\nRequires Node.js ≥ 20.\n\nFor interactive login you also need `gcloud` installed once. The CLI uses it only for the OAuth browser flow — never to enable APIs, list projects, or set quota. If `gcloud` is missing, `gsc auth login` prints the install command for your platform.\n\n| Platform | Install command |\n|---|---|\n| macOS | `brew install --cask google-cloud-cli` |\n| Windows | `winget install Google.CloudSDK` |\n| Linux / other | https://cloud.google.com/sdk/docs/install |\n\n\u003e **Headless / CI users**: skip `gcloud` entirely. Create a service account in your GCP project, grant it access to your Search Console property, download the JSON key, and `export GOOGLE_APPLICATION_CREDENTIALS=/path/to/key.json`. Every `gsc` command except `auth login` will use it automatically.\n\n## Quick start\n\n```bash\n# 1. Authenticate (opens browser, picks/enables a project, persists quota)\ngsc auth login\n\n# 2. List your verified sites\ngsc sites list\n\n# 3. Set a default site so you don't repeat --site every time\ngsc config set defaultSite sc-domain:example.com\n\n# 4. Pull the last 30 days of search analytics, top 50 queries\ngsc analytics query --days 30 --dimension query --limit 50\n\n# 5. Inspect a single URL\ngsc inspect https://example.com/blog/launch\n\n# 6. Inspect every URL in your sitemap, just the ones with errors\ngsc inspect --sitemap --filter errors --concurrency 8\n```\n\n## Authentication\n\n`gsc auth login` does the entire OAuth + project-selection dance:\n\n1. **Opens a browser** via `gcloud auth application-default login` for the OAuth handshake. (gcloud is the OAuth identity — we never use it for anything else.)\n2. **Clears any stale `quota_project_id`** that gcloud may have carried over from a previous account, so the next API calls aren't poisoned by a header your fresh credentials lack permission for.\n3. **Lists your accessible GCP projects** via the Cloud Resource Manager REST API using your fresh ADC credentials.\n4. **Probes Search Console API** on each project with an explicit `x-goog-user-project` header. The first project where the API is already enabled wins — no propagation delay.\n5. **Auto-enables the API** if no project has it on. Calls `serviceusage.services.enable` per project until one succeeds. Falls back to a clear error with a console link if none can be enabled (e.g. for accounts that only have auto-created Google service projects where Service Usage isn't bootstrapped).\n6. **Persists the quota project** by writing `quota_project_id` directly to your ADC file (`~/.config/gcloud/application_default_credentials.json`). Subsequent `gsc` calls inherit it automatically through `google-auth-library`.\n\nOverride auto-selection at any time with `--project`:\n\n```bash\ngsc auth login --project my-gcp-project\n```\n\nOther auth commands:\n\n```bash\ngsc auth status   # show whether ADC is loaded and which account\ngsc auth whoami   # alias for status\ngsc auth logout   # revoke ADC credentials\n```\n\n## Commands\n\nAll commands accept `--format json|text|table` and most that target a site accept `--site sc-domain:example.com` (or set `defaultSite` once via `gsc config`).\n\n### `gsc sites`\n\nManage verified sites in your Search Console property.\n\n```bash\ngsc sites list                                  # list all verified sites\ngsc sites get --site sc-domain:example.com      # fetch one\ngsc sites add https://example.com/              # add and start verification\ngsc sites delete https://example.com/           # remove\n```\n\n### `gsc sitemaps`\n\n```bash\ngsc sitemaps list                               # all sitemaps for the default site\ngsc sitemaps get https://example.com/sitemap.xml\ngsc sitemaps submit https://example.com/sitemap.xml\ngsc sitemaps delete https://example.com/sitemap.xml\n```\n\n### `gsc analytics query`\n\nThe workhorse. Pulls rows from the `searchAnalytics.query` endpoint with full dimension and filter support.\n\n```bash\n# Last 30 days, top 100 queries\ngsc analytics query --days 30 --dimension query --limit 100\n\n# Explicit date range, grouped by page + country\ngsc analytics query --start 2026-01-01 --end 2026-01-31 \\\n  --dimension page,country\n\n# Filter to /blog/ URLs from the US, image search type\ngsc analytics query --days 7 --dimension query \\\n  --filter 'page~/blog/,country=USA' --type image\n```\n\n**Filter operators** (parsed in order of specificity, longest first):\n\n| Operator | Meaning |\n|---|---|\n| `=` | equals |\n| `!=` | notEquals |\n| `~` | contains |\n| `!~` | notContains |\n| `=~` | includingRegex |\n| `!=~` | excludingRegex |\n\nMultiple filters are comma-separated. `--limit` above 25,000 auto-paginates.\n\n### `gsc inspect`\n\nURL inspection — single or batch.\n\n```bash\n# Inspect one URL\ngsc inspect https://example.com/blog/launch\n\n# Inspect every URL from your sitemap, parallelised\ngsc inspect --sitemap --concurrency 8\n\n# Show only URLs with indexing problems\ngsc inspect --sitemap --filter errors\n\n# Filter values: indexed | not-indexed | errors\n```\n\n`--concurrency` defaults to 4 and respects the SDK's token-bucket rate limiter so you won't trip API quotas.\n\n### `gsc config`\n\n```bash\ngsc config set defaultSite sc-domain:example.com\ngsc config set defaultFormat table\ngsc config set quotaProjectId my-gcp-project\ngsc config get                          # print full config\ngsc config get defaultSite              # print one key\ngsc config path                         # print config file path\n```\n\nConfig lives at `~/.config/gsc/config.json` (file mode `0600`).\n\n### `gsc doctor`\n\nSanity-checks your environment: ADC presence, config validity, API reachability.\n\n```bash\ngsc doctor\n```\n\n## Output envelope\n\nEvery command — success or failure — emits the same JSON shape:\n\n```jsonc\n// success\n{\n  \"ok\": true,\n  \"data\": [ /* command-specific payload */ ],\n  \"meta\": {\n    \"command\": \"sites list\",\n    \"durationMs\": 412,\n    \"rateLimit\": { \"remaining\": 997, \"resetAt\": \"2026-04-13T18:00:00.000Z\" }\n  }\n}\n\n// error\n{\n  \"ok\": false,\n  \"error\": {\n    \"code\": \"AUTH_FAILED\",\n    \"message\": \"no project has Search Console API enabled and auto-enable failed\",\n    \"hint\": \"Enable Search Console API at https://console.cloud.google.com/...\",\n    \"httpStatus\": 403\n  },\n  \"meta\": { \"command\": \"auth login\", \"durationMs\": 17661 }\n}\n```\n\nError codes are stable: `AUTH_MISSING`, `AUTH_FAILED`, `BAD_ARGS`, `NOT_FOUND`, `PERMISSION_DENIED`, `RATE_LIMITED`, `VALIDATION_ERROR`, `SERVER_ERROR`, `NETWORK_ERROR`. `--format text` and `--format table` render the same payload for humans.\n\n## Using the SDK directly\n\nIf you'd rather call the API from Node, the underlying SDK is published as `@gsc-cli/sdk`:\n\n```ts\nimport { GSCClient } from '@gsc-cli/sdk'\n\nconst client = await GSCClient.fromCachedAuth()\nconst sites = await client.sites.list()\n\nconst rows = await client.analytics.query({\n  siteUrl: 'sc-domain:example.com',\n  startDate: '2026-01-01',\n  endDate: '2026-01-31',\n  dimensions: ['query', 'page'],\n  rowLimit: 5000,\n})\n```\n\n`fromCachedAuth()` reads your ADC credentials. For service accounts, set `GOOGLE_APPLICATION_CREDENTIALS` and call the same factory. For full control, instantiate `new GSCClient({ auth, quotaProjectId, retry, rateLimit, cache, ... })` directly.\n\nThe SDK includes:\n\n- **`HttpClient`** with bounded retries on `429` and `5xx`.\n- **`TokenBucket`** rate limiter, configurable per resource.\n- **`MemoryCache`** with TTL for `GET` responses.\n- Typed errors (`GSCAuthError`, `GSCRateLimitError`, `GSCNotFoundError`, etc.) you can `instanceof`.\n\n## Repository layout\n\n```\ngsc-cli/\n├── packages/\n│   ├── cli/              # CLI binary, command modules, output envelope\n│   │   ├── src/\n│   │   │   ├── bin.ts          # citty entry point\n│   │   │   ├── commands/       # one file per top-level command\n│   │   │   ├── output/         # envelope + format renderers\n│   │   │   ├── runner.ts       # error → envelope translation\n│   │   │   ├── config.ts       # ~/.config/gsc/config.json loader\n│   │   │   └── sitemap/        # sitemap.xml fetch + parse\n│   │   └── test/               # vitest unit + integration suites\n│   └── sdk/              # @gsc-cli/sdk — typed Node client\n│       └── src/\n│           ├── client.ts\n│           ├── resources/      # sites, sitemaps, analytics, inspection\n│           ├── transport/      # http-client, retry, rate-limit, cache\n│           └── errors.ts\n├── prd/                  # design docs\n├── pnpm-workspace.yaml\n└── package.json\n```\n\n## Development\n\nRequires Node ≥ 20 and pnpm 9.\n\n```bash\npnpm install\npnpm build         # build all packages (tsup)\npnpm test          # vitest unit suites across the workspace\npnpm typecheck     # tsc --noEmit on src + test configs\n```\n\nPer-package:\n\n```bash\npnpm --filter @gsc-cli/cli build\npnpm --filter @gsc-cli/cli test\npnpm --filter @gsc-cli/sdk test\n```\n\nRun the local CLI against your own Search Console account without globally installing:\n\n```bash\npnpm --filter @gsc-cli/cli build\nnode packages/cli/dist/bin.js sites list\n```\n\n## Contributing\n\nIssues and PRs welcome. Please:\n\n1. Open an issue first for non-trivial changes so we can agree on the shape.\n2. Add or update tests — every command module has a corresponding `test/commands/*.test.ts` file.\n3. Run `pnpm typecheck \u0026\u0026 pnpm test` before pushing.\n4. Keep commit messages descriptive; we use Changesets for release notes.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawkoy%2Fgsc-cli","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fawkoy%2Fgsc-cli","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fawkoy%2Fgsc-cli/lists"}