Skip to main content
People also find an app through its website: in Google, in Google’s AI Overviews, and in the pages AI assistants cite. These commands check the site, record how it does in Google, and let verify measure a listing change that also changes the website’s copy.

Point the spec at the site

seo check

Reads the page the way a crawler does. It needs no key and no account.
✓ is fine, ! is a warning, ✗ fails. Any ✗ makes it exit 1, so you can run it in CI. A site that does not answer, or answers with an HTTP error, fails at once: check web.url.

seo llms

Writes llms.txt from the listing: the app’s name and subtitle, the first paragraph of the description, links to the App Store, Google Play, the website and support, the first storefront’s target keywords as “Good for”, and the full description. Without --out it prints it. Run it again after a listing change so the site and the store say the same thing.

Search Console: seo pull

seo pull reads Google Search Console with your own Google credentials, in this order:
  1. GSC_CREDENTIALS: a service account JSON key, or its path. Create the service account in Google Cloud, enable the Search Console API, and add its email as a user of the property in Search Console.
  2. GOOGLE_APPLICATION_CREDENTIALS, the same way. In CI this is often your Google Play service account; it works for Search Console once its email is a user of the property.
  3. Your gcloud login on this machine: gcloud auth application-default login --scopes=https://www.googleapis.com/auth/webmasters.readonly,https://www.googleapis.com/auth/cloud-platform.
Search Console data settles after about two days, so the window ends two days ago. It writes to appeeky/seo/: The close-to-the-top queries are the cheapest wins: a better title, description or section can move them onto the first screen. A 403 means the account is not a user of the property yet.

Google ranks and AI Overviews on DataForSEO

With your own DataForSEO account, Spec reads Google’s results page itself. Set DATAFORSEO_LOGIN and DATAFORSEO_PASSWORD from its API access page. DataForSEO bills each call. Each one quotes first and asks before spending:
--dry-run works before the keys are set. --yes skips the question. The real cost of each run is printed at the end.
  • seo ranks reads the top 100 results for each keyword. site is the best position of any page on your site, store page is where the app’s App Store or Google Play page ranks on Google. ranks.csv gets one row per keyword per check (date,country,keyword,position,url,store_position,ai_overview,ai_cites_you); a second check on the same day replaces the first. Keywords entering or leaving the top 10, and AI Overview citations gained or lost, go to changes.md. --every <days> skips the check when the last one is newer.
  • seo keywords writes volume, difficulty, CPC and intent for your keywords, plus up to 50 related ideas from each of the first three, to keywords.csv (tracked is yes for yours).
  • seo domain reports for the first watched storefront: how many keywords the site ranks for, how many in the top 3 and top 10, estimated monthly visits, the top keywords (marking store targets), and sites that rank for the same searches.
When Google shows an AI Overview that cites other sites but not yours, those are the pages to beat: compare their copy with yours, and run seo check for the AI crawler items.

What verify reads

Experiments can use them too: experiment add --metric web_rank. See Push, measure and revert.

On a schedule

The daily workflow and the Docker daily routine run seo pull when GSC_CREDENTIALS is set, and seo ranks --every 7 --yes when DATAFORSEO_LOGIN is set (SEO_RANKS_EVERY changes the days). seo keywords and seo domain are for when you plan copy; run them by hand. The weekly agent cannot run the paid ones with --yes. See GitHub Actions & CI. Related: AI answers · On your own keys · GitHub Actions & CI