agentsclimarketplace

SEMRUSH API Skill for Claude

Skill tvirelli/SEMRUSH-API-Skill-for-Claude

Work with the SEMRush REST API (SEO/Analytics reports, Site Audit, Projects, Position Tracking, Trends, Local) while strictly conserving API units. Use whenever the user mentions SEMRush, semrush.com API, API units/credits, position tracking, site audit, keyword/domain/backlink reports, or competitor research via SEMRush.From its SKILL.md

Install
npx -y skills add tvirelli/SEMRUSH-API-Skill-for-Claude

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.6 KB, ~3.0k tokens by cl100k_base, as published. Nobody here has run it

SEMRush API

This skill wraps the raw SEMRush REST API (developer.semrush.com) behind a single CLI, scripts/semrush.py. It exists to stop two failure modes: burning a client's API unit balance on exploratory or repeated calls, and firing off a write (POST/PUT/PATCH/DELETE) the user never actually approved. Do not use the SEMRush MCP server for this work even if it is connected in the current session - this skill is raw-REST-only so every call goes through the cache and cost-visibility layer below. If the SEMRush MCP appears in your tool list, ignore it for anything this skill covers.

Every instruction below is mandatory operating procedure, not a suggestion.

1. The conservation contract

Follow these six rules on every single request, with no exceptions:

  1. Cache first. Before any network call, scripts/semrush.py get checks its local cache. Same-day data is reused at zero cost automatically - you do not need to ask the user, and you should not bypass this by hand. Only pass --fresh when the user explicitly needs data newer than today's cached copy.
  2. Know before you call. Read the relevant references/*.md file for the exact endpoint path, required and optional parameters, and cost class before you build any request. Never make an exploratory or "let's see what comes back" call against a live endpoint. If you are not sure which reference file covers the question, use the routing table in section 2 below, not trial and error against the API.
  3. Cost knowledge is the top priority. Every endpoint you touch must be labeled one of FREE, METERED (with an explicit units-per-line figure), or QUOTA before you call it - see section 5. For any report where cost scales with rows returned, trim display_limit (and export_columns to only the fields you need) before calling, not after. Never issue a metered call with an unbounded or default display_limit.
  4. One shot, verified. Build the request, check it against the reference file one more time, then call it once. There is no retry loop anywhere in this skill. If the call errors, diagnose the failure from the response text and the reference file's error-code notes; fix the request and make a deliberate second call only if the diagnosis points to a specific, correctable mistake. Do not loop blindly hoping a retry succeeds.
  5. Writes need an explicit yes from the user. The CLI enforces this mechanically: write without --confirm prints the exact request (key masked) and exits without sending anything. Never add --confirm on your own initiative - only after the user has clearly approved the specific write you showed them. For DESTRUCTIVE writes - deletes, replace-semantics updates such as the Position Tracking competitors PUT, or anything else that discards existing history or configuration - you must additionally state the concrete, irreversible consequence ("this replaces the entire competitor list; the old list cannot be recovered") and get the user's explicit yes to that consequence before you even show them the --confirm step.
  6. Report actual lines returned after each metered call. The CLI prints the real data-line count to stderr ([FETCHED] ~N data lines returned). Relay that number to the user so they can see actual spend versus the pre-call estimate, not just take your word that the call "worked."

2. Which API answers this question?

Route the user's question to exactly one reference file and read only that file. Do not read multiple reference files "just in case."

QuestionAPIReference
"How does domain X rank / what keywords / backlinks does it have?"SEO (Analytics) APIreferences/seo-api.md
"What is broken on MY site?"Site Auditreferences/site-audit.md
"Where do MY tracked keywords rank daily?"Position Tracking (Projects)references/projects.md
"Create/configure projects or campaigns"Projects managementreferences/projects.md
"Market/traffic trends for any site"Trends APIreferences/trends-api.md
"Local listings / map rankings"Local APIreferences/local-api.md

If a question spans two rows (for example, "audit my site and see how a competitor ranks"), treat it as two separate lookups against two separate reference files - do not guess at a combined call. Basics that apply across all APIs (auth, units, error codes, supported databases, common filters) live in references/basics.md; check it first if the question is about mechanics rather than a specific report.

3. Profile mechanism

Account-specific data (which project is the user's, which domain, which campaign IDs) never lives in this skill's files - it lives in a profile file that the user's own working directory or environment supplies.

Lookup order, first match wins:

  1. --profile <path> flag passed to the CLI
  2. SEMRUSH_PROFILE environment variable (path to the profile file)
  3. ./.semrush/profile.json (relative to the current working directory)

Example profile file:

{
  "key_file": "credentials/semrush_api_key.txt",
  "project_id": 123456,
  "domain": "example.com",
  "position_tracking_campaigns": {
    "desktop": "123456_1111111",
    "mobile": "123456_2222222"
  }
}

key_file is a path to a file containing the raw API key, never the key itself. If key_file is a relative path, it resolves against the profile file's parent directory's parent directory (that is, a profile at <project>/.semrush/profile.json resolves a relative key_file against <project>/, not against <project>/.semrush/). The profile therefore never holds the key value, only paths and IDs, so it is safe to keep in a repo that gets shared or committed.

Bootstrap procedure

If no profile file can be found at any of the three lookup locations, do not guess at IDs or ask the user to paste their API key into chat. Instead:

  1. Ask the user where their API key file lives on disk (a plain text file containing just the key).
  2. Confirm you can reach the account with a MANAGEMENT-class call (references/projects.md section 1 field note documents this specific endpoint) - a management-class call; not priced in the current docs - treat as cheap but not proven free: python scripts/semrush.py get /management/v1/projects --keyfile <path>
  3. Show the user the list of projects/domains returned and ask which one is theirs.
  4. If the user does Position Tracking work, also list that project's campaigns so you can capture the compound campaign IDs (they are not plain integers - see references/projects.md) into the profile.
  5. Write .semrush/profile.json with key_file (path, not the key), project_id, domain, and any campaign IDs gathered, then show the user the file's contents and get their confirmation that it is correct before relying on it for further calls.

4. The CLI

All calls go through scripts/semrush.py. stderr carries operational metadata (cache hits, cost estimates, fetch confirmations, dry-run output). For get and write commands, stdout carries only the raw response body. For cache list, stdout prints entry metadata (timestamps, endpoints, params, file sizes). stdout is always safe to pipe or capture on its own.

get - cached GET request

python scripts/semrush.py get <endpoint> --params k=v [k=v ...] [--fresh] [--ttl HOURS] [--dry-run] [--profile PATH] [--keyfile PATH]
  • <endpoint> is the API path, e.g. /management/v1/projects or / for the classic Analytics endpoint.
  • --params k=v ... supplies query parameters as space-separated key=value pairs.
  • Default behavior: check the cache first. On a hit, stderr prints [CACHE HIT - 0 units] fetched <timestamp> and stdout prints the cached body - no network call is made.
  • --fresh skips the cache read entirely and forces a live call (the response is still cached afterward for next time).
  • --ttl HOURS overrides the default cache validity window. Without it, a cached entry is valid only through the end of the calendar day it was fetched on; --ttl extends (or shrinks) that window in hours from the fetch timestamp.
  • --dry-run builds and prints the full request URL (key masked as ***) to stderr. On a cache miss, it stops and shows the preview without any network call or cache write. On a cache hit, the cached response is returned (no preview shown). To guarantee a preview of the exact request URL, use --fresh --dry-run together.
  • --profile PATH / --keyfile PATH override the normal profile/key lookup order for this one call. The key is resolved in this order: --keyfile flag, SEMRUSH_API_KEY environment variable, then key_file path from the profile.
  • On a live fetch, stderr prints the pre-call cost estimate ([COST <CLASS>] ...) before the request goes out, then [FETCHED] ~N data lines returned; cached for today after it returns.
  • On an HTTP error or a body starting with ERROR, stderr prints the status and response text and the process exits non-zero. There is no automatic retry - diagnose from that text against the reference file before trying again.

write - confirm-gated POST/PUT/PATCH/DELETE, never cached

python scripts/semrush.py write <endpoint> --method POST|PUT|PATCH|DELETE [--body '<json>'] [--params k=v ...] [--profile PATH] [--keyfile PATH] [--confirm]

Every write template in references/*.md is preview-first: copied and run verbatim, it prints the exact request and exits without sending. Append --confirm only after the user has approved the previewed request (and, for DESTRUCTIVE writes, been told the consequence) - never add it on your own initiative.

  • Without --confirm: stderr prints the masked request (method, URL, and the JSON body if any) and the process exits with status 2. Nothing is sent. This is the mechanism that enforces rule 5 of the contract - show this output to the user verbatim and get their explicit approval before ever adding --confirm.
  • With --confirm: the request is actually sent; stderr prints the HTTP status and stdout prints the response body.
  • Writes are never read from or written to the cache.

cache list|clear

python scripts/semrush.py cache list
python scripts/semrush.py cache clear
  • list prints every cached entry's fetch timestamp, endpoint, a truncated view of its params, and its file size on stdout.
  • clear deletes every cached entry and reports how many were removed on stderr.
  • The API key is never written into cache files or cache keys under any circumstance - parse_params also hard-rejects a literal key= value passed via --params (exits before the call is built), so there is no path by which a key ends up in a cache file.

5. Cost classes

Every endpoint you call must fall into one of these labeled classes before you build the request. If you cannot label it, you have not read the reference file closely enough yet.

  • FREE - no unit cost. Still make the call deliberately (rule 4), not repeatedly.
  • METERED (N units/line) - cost scales with the number of data lines returned, at a fixed per-line rate that varies by report type. Analytics report prices live in the ANALYTICS_COST dict in scripts/semrush.py (keyed by report type) and are restated in the relevant reference file. Always set display_limit before calling a METERED endpoint; an unbounded call is reported by the CLI as "METERED: UNBOUNDED x {per} units/line - SET display_limit before calling" and should not be sent as-is.
  • QUOTA - consumes against a separate quota rather than a per-line unit price (for example, Site Audit page-crawl quotas or Projects slot limits). Quota rules are documented per endpoint in the owning reference file - read them before calling, since quota is not always visible as a simple number the way unit cost is.
  • MANAGEMENT / PROJECT-REPORT - the CLI's classify() function auto-labels any endpoint under /management/v1/ or /reports/v1/projects/ with these classes as a first pass; treat them as a pointer to "read references/projects.md for this endpoint's real quota/unit rules," not as a final cost answer.
  • UNKNOWN - the CLI could not classify the endpoint or report type at all. This is a hard stop: do not call it. Go read the reference file for that endpoint, find its documented cost, and only then build the request.

What ships with it: 21 files

266.5 KB alongside SKILL.md, 2 of them executable

references/

scripts/

Gives 0 of the 12 instructions most seo skills give in ~3.0k tokens

Counted across 454 of the 460 authors here whose files we hold, read 2026-08-07

  • Implement structured data using JSON-LDin 29 of 454, across 25 files
  • Write unique meta descriptions under 160 charactersin 25 of 454, across 20 files
  • Verify one H1 exists per pagein 24 of 454, across 15 files
  • Maintain a single H1 per pagein 24 of 454, across 15 files
  • Use JSON-LD format for all schema markupin 23 of 454, across 16 files
  • Use descriptive anchor text for internal linksin 22 of 454, across 18 files
  • Add descriptive alt text to imagesin 19 of 454, across 15 files
  • Read product marketing context before auditingin 19 of 454, across 11 files
  • Write unique title tags under 60 charactersin 19 of 454, across 14 files
  • Add unique title and meta description per pagein 19 of 454, across 17 files
  • Fetch robots.txt and sitemap.xmlin 19 of 454, across 18 files
  • Place the primary keyword in the first 100 wordsin 18 of 454, across 17 files

Said here and by no other author read

  • Use the provided CLI for all API calls
  • Check the local cache before making network calls
  • Read the relevant reference file before building any request
  • Label the cost class of every endpoint before calling
  • Trim display limit and export columns before calling metered endpoints
  • Verify the request against the reference file before calling

Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.

Keep looking

Skills are one crate of 326,452. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.