Google Merchant Center CLI for the Merchant API v1 — products, feeds, reports, promotions. JSON output, jq-friendly.
Project description
gmc-cli — Google Merchant Center CLI
A standalone command-line client for the Google Merchant API v1
(merchantapi.googleapis.com) — the GA replacement for the Content API for
Shopping, which Google retires in August 2026.
Drive your Merchant Center from the terminal (or from an AI agent): products,
feeds, performance reports, price benchmarks, promotions, account settings.
One auditable codebase, credentials never leave your machine, all output is
JSON on stdout — pipe it to jq.
pipx install gmc-cli
gmc auth login --client-id=… --client-secret=… --merchant-id=1234567890
gmc register-gcp # one-time Google requirement, see below
gmc products issues-summary | jq '.top_issue_codes'
gmc report performance --start 2026-06-01 --end 2026-06-30 --order-by clicks
Why
- CLI, not SaaS: no third-party service proxies your Merchant Center data.
- Merchant API v1: built on the new GA API, not the deprecated Content API v2.1.
- Read-first safety model: only three write commands exist, deletes require
--yes, and a global--dry-runprints the exact HTTP request instead of sending it. - Agent-friendly: predictable JSON output and one flat command tree make it easy to hand to Claude/other AI agents as a tool.
Install
pipx install gmc-cli # recommended (isolated)
# or: pip install gmc-cli
From source:
git clone https://github.com/almoretti/gmc-cli && cd gmc-cli
./setup.sh # local venv + editable install; run via ./gmc
Setup
1. Create an OAuth client (one-time, ~3 minutes)
- Go to Google Cloud Console → pick or create a project.
- Enable the Merchant API.
- APIs & Services → Credentials → Create Credentials → OAuth client ID → Desktop app. Copy the client ID and secret.
- If the OAuth consent screen is in Testing mode, add yourself as a test user (and note refresh tokens expire after 7 days until you publish the app to In production).
2. Log in
gmc auth login --client-id=xxx --client-secret=xxx --merchant-id=1234567890
Opens a browser — sign in with a Google account that has access to your
Merchant Center (the numeric merchant ID is in the top-right of
merchants.google.com). Credentials are saved
to ~/.config/gmc-cli/credentials.json (chmod 600) and refresh automatically.
3. Register your GCP project (one-time, mandatory)
Google requires the GCP project behind your OAuth client to be registered as a developer with the merchant account, or every API call returns 401:
gmc register-gcp --developer-email you@example.com
gmc auth check # should print your account name and "ok": true
Idempotent — safe to re-run.
Alternative credentials
- Service account (headless automation): set
GMC_SERVICE_ACCOUNT_KEYto a JSON key path, and add the service account's email as a user in Merchant Center → Settings → People and access. - Env/dotenv:
GMC_ACCOUNT_ID,GMC_SUBACCOUNT_ID(act on an MCA sub-account),GMC_OAUTH_TOKEN. A.envin the working directory is read. - ADC fallback:
gcloud auth application-default loginwith thecontentscope.
Resolution order: GMC_SERVICE_ACCOUNT_KEY → GMC_OAUTH_TOKEN →
~/.config/gmc-cli/credentials.json → ADC. Merchant ID: --merchant-id →
GMC_SUBACCOUNT_ID/GMC_ACCOUNT_ID → saved config.
Commands
gmc auth login | check | init --client-secrets FILE
gmc register-gcp [--developer-email EMAIL] # one-time per GCP project
gmc account get | list | issues | users | programs | shipping | homepage | business-info
gmc products list [--limit N] [--full]
gmc products get|status ID # ID = contentLanguage~feedLabel~offerId
gmc products disapproved # all disapproved products (via Reports)
gmc products issues-summary # issue codes ranked by frequency
gmc products insert --product @p.json --data-source accounts/…/dataSources/… (WRITE)
gmc products delete ID --data-source … --yes (WRITE)
gmc report query "SELECT … FROM product_performance_view WHERE …"
gmc report performance --start YYYY-MM-DD --end YYYY-MM-DD [--order-by clicks] [--top N]
gmc report zero-clicks [--min-impressions N] [--start …] [--end …]
gmc report price-competitiveness | price-insights | demoted
gmc report best-sellers [--country GB] [--granularity WEEKLY|MONTHLY]
gmc report competitors [--country GB] [--category 469] [--traffic-source ALL|ADS|ORGANIC]
gmc datasources list | get ID | fetch ID # fetch = WRITE, triggers feed re-crawl
gmc promotions list | get ID
gmc regions | quotas | return-policies
gmc raw GET|POST|PATCH|PUT|DELETE <path> [--body JSON] [--param k=v] # escape hatch
Global flags: --merchant-id ID, --dry-run (print writes instead of
sending), -v (retry diagnostics), --version.
Defaults note: report shortcuts default to --country GB and --category 469
(Health & Beauty) — override for your market
(category IDs).
Examples
# What's broken in my feed, ranked by issue code?
gmc products issues-summary | jq '.top_issue_codes'
# Top products by clicks, last 30 days, as TSV
gmc report performance --start 2026-06-09 --end 2026-07-08 \
| jq -r '.results[].productPerformanceView | [.offerId, .clicks, .impressions] | @tsv'
# Where am I priced above the market benchmark?
gmc report price-competitiveness | jq '.results[].priceCompetitivenessProductView
| select((.price.amountMicros|tonumber) > (.benchmarkPrice.amountMicros|tonumber))'
# Force an immediate re-fetch of a scheduled feed
gmc datasources list | jq -r '.dataSources[].dataSourceId'
gmc datasources fetch 123456789
# Preview a product upsert without sending it
gmc --dry-run products insert --product @sku.json --data-source accounts/…/dataSources/…
# Anything the built-ins don't cover
gmc raw GET conversions/v1/accounts/1234567890/conversionSources
Safety model
- Reads are unrestricted; writes exist only for
products insert/deleteanddatasources fetch; delete requires--yes. - Global
--dry-runshort-circuits any write and prints the exact request. - Retries with exponential backoff +
Retry-Afteron 429/5xx. gmc rawcan perform any method — use deliberately.- Product inserts only work against API-type data sources; feeds fetched from
files/Sheets can't be written via the API (use
datasources fetchto trigger re-crawls instead, or overlay a supplemental API data source).
Merchant API v1 notes (learned the hard way)
- Product IDs:
contentLanguage~feedLabel~offerId(e.g.en~GB~SKU123). - Product writes go through
productInputs:insert(upsert — full body overwrites) and always require adataSource. - v1 vs v1beta field changes:
gtin→gtins(list),attributes→productAttributes, enums are UPPER_CASE strings,channel/taxesremoved. - Report dialect rules (all verified live; the built-in shortcuts handle them):
ctr→click_through_rate;conversion_value_micros→conversion_valueproduct_performance_viewrequires adatecondition in WHEREprice_competitiveness_product_viewrequiresreport_country_code+idin SELECTprice_insights_product_viewrequiresidin SELECTbest_sellers_*requiresreport_date,report_granularity,report_country_code,report_category_idin SELECT and areport_granularityWHERE conditioncompetitive_visibility_*requiresreport_country_code,report_category_id,traffic_sourcein SELECT and WHERE conditions ondate,report_category_id,traffic_source
Testing
./test.sh runs a 45-check functional suite against whatever merchant account
you're logged into: every read command live, every write in --dry-run only,
plus the guard rails. It never mutates your feed.
Acknowledgements
Endpoint conventions were originally mapped out by studying kiwoongeom/gmc-mcp (MIT), an MCP server for the same API. No code was copied; this project exists for people who want a plain CLI with no MCP layer.
License
Apache-2.0
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file gmc_cli-0.1.0.tar.gz.
File metadata
- Download URL: gmc_cli-0.1.0.tar.gz
- Upload date:
- Size: 20.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6ac4007028d81cb2ea9d01558024ffd889a4fccab3907e9bb98dba10f4f17b9f
|
|
| MD5 |
44954759008310738695b9b19a2253ca
|
|
| BLAKE2b-256 |
63d685ab73cf942f54567ef591f11ee618c9e6acd1d3202791ac16c3375e7753
|
Provenance
The following attestation bundles were made for gmc_cli-0.1.0.tar.gz:
Publisher:
publish.yml on almoretti/gmc-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gmc_cli-0.1.0.tar.gz -
Subject digest:
6ac4007028d81cb2ea9d01558024ffd889a4fccab3907e9bb98dba10f4f17b9f - Sigstore transparency entry: 2128081500
- Sigstore integration time:
-
Permalink:
almoretti/gmc-cli@e77b17ee097019f449fa22e62045d7e844300f9c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/almoretti
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e77b17ee097019f449fa22e62045d7e844300f9c -
Trigger Event:
release
-
Statement type:
File details
Details for the file gmc_cli-0.1.0-py3-none-any.whl.
File metadata
- Download URL: gmc_cli-0.1.0-py3-none-any.whl
- Upload date:
- Size: 18.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
de413b05bf0a06f8ac85e407c1e2a03c58c6cf57959b483fbc10136d857a567f
|
|
| MD5 |
f6bd74f49fd6107fd5f7a251bfdfef84
|
|
| BLAKE2b-256 |
5f66bcba5eb5288bbbcf5d44eb96baf235ee24fea853547f667ce9d2559787c4
|
Provenance
The following attestation bundles were made for gmc_cli-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on almoretti/gmc-cli
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gmc_cli-0.1.0-py3-none-any.whl -
Subject digest:
de413b05bf0a06f8ac85e407c1e2a03c58c6cf57959b483fbc10136d857a567f - Sigstore transparency entry: 2128081597
- Sigstore integration time:
-
Permalink:
almoretti/gmc-cli@e77b17ee097019f449fa22e62045d7e844300f9c -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/almoretti
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e77b17ee097019f449fa22e62045d7e844300f9c -
Trigger Event:
release
-
Statement type: