RankParse

Client report

Read the weekly client report for a website, built from search clicks, rank moves and the work your agent did.

GET/v1/client-reportFreeAPI key

The client report is a one-week summary of a website that you can show to a client or stakeholder: how many search clicks the site got, how many tracked keywords moved up or down, and a short list of the work that was done (IndexNow submissions, outreach emails sent, notes your team chose to share).

The same data powers the Report page in the dashboard, including its client preview and PDF download. This endpoint returns the data as JSON. It is a stored-data read, not a live check, and it is not an MCP tool.

Request

Parameters

ParameterTypeRequiredDefaultDescription
site_idstringYesnoneA website id from GET /v1/websites.
week_startstringNothe current weekThe Monday that starts the week, as YYYY-MM-DD in UTC. It must be a real Monday and not in the future.

Weeks run Monday 00:00 UTC to the following Monday 00:00 UTC.

Example

curl "https://api.rankparse.com/v1/client-report?site_id=site_abc123&week_start=2026-09-28" \
  -H "X-API-Key: rp_your_key"
import requests

res = requests.get(
    "https://api.rankparse.com/v1/client-report",
    headers={"X-API-Key": "rp_your_key"},
    params={"site_id": "site_abc123", "week_start": "2026-09-28"},
)
data = res.json()
print(data["frozen"], data["report"]["kpis"])
const params = new URLSearchParams({
  site_id: "site_abc123",
  week_start: "2026-09-28",
});
const res = await fetch(`https://api.rankparse.com/v1/client-report?${params}`, {
  headers: { "X-API-Key": "rp_your_key" },
});
const { report, frozen } = await res.json();
console.log(frozen, report.kpis);

Response

{
  "report": {
    "week_start": "2026-09-28",
    "kpis": {
      "clicks_28d": 4210,
      "clicks_prev_28d": 3874,
      "queries_up": 18,
      "queries_down": 7,
      "window_end": "2026-10-01"
    },
    "events": [
      {
        "id": "act_Qm3N8vLp2Xw5Zt9RbYk1C",
        "verb": "indexnow.submitted",
        "occurred_at": 1790596800000,
        "params": { "url_count": 12, "host": "example.com" },
        "agent_text": null
      },
      {
        "id": "act_Zr7Tn4Kc9Ve2Ls6HdWq8M",
        "verb": "rank.moves_detected",
        "occurred_at": 1790683200000,
        "params": { "up": 5, "down": 2, "date": "2026-09-29" },
        "agent_text": null
      },
      {
        "id": "act_Bp1Yw5Mj3Ux8Gf2NaCt6E",
        "verb": "outreach.sent_daily",
        "occurred_at": 1790769600000,
        "params": { "count": 20, "date": "2026-09-30" },
        "agent_text": null
      }
    ]
  },
  "frozen": true
}

Response fields

FieldTypeDescription
report.week_startstringThe Monday the report covers.
report.kpis.clicks_28dinteger or nullGoogle clicks in the 28 days ending on window_end. null when the website has no active primary Google Search Console property.
report.kpis.clicks_prev_28dinteger or nullGoogle clicks in the 28 days before that window, for comparison. null in the same case.
report.kpis.queries_upintegerTracked-keyword moves up detected during the week (entering the top 3 or top 10, moving up, new rankings).
report.kpis.queries_downintegerTracked-keyword moves down detected during the week (leaving the top 3 or top 10, moving down, lost rankings).
report.kpis.window_endstringLast day of the current 28-day window, YYYY-MM-DD. Always present.
report.eventsobject[]The week's client-visible activity, oldest first, at most 500.
report.events[].idstringActivity id (act_...).
report.events[].verbstringWhat happened. See the table below.
report.events[].occurred_atintegerUnix time in milliseconds.
report.events[].paramsobjectA small set of fields per verb. Anything else is stripped.
report.events[].agent_textstring or nullText written by an agent, present only when a team member shared it with the client.
frozenbooleantrue when the week was published and is served from its saved snapshot; false when it was computed just now.

Events a client can see

VerbparamsMeaning
indexnow.submittedurl_count, hostURLs were submitted to IndexNow.
outreach.sent_dailycount, dateOutreach emails were sent that day.
rank.moves_detectedup, down, dateTracked keywords moved up or down that day.
agent.note, task.completednoneA note or task summary a team member chose to share. The text is in agent_text.

Internal activity (approvals, policy changes, call counts, credits, team and client changes) is never part of a client report. An agent note or task summary stays private to the team until someone shares it.

How a week is produced

  • Current or open week: computed from live data on every request (frozen: false). Numbers can change as the week goes on.
  • Published week: every Monday from 07:00 UTC, an hourly job saves the previous week for each website that had client-visible activity in it. Once saved, that week never changes, even if an event is added to it later, and requests for it return frozen: true.
  • No activity that week: a website with search data but no client-visible events is not saved, so it is computed live each time and is always frozen: false.
  • Search data lag: both 28-day windows end 3 days before the last day of the week, so the click numbers are complete and do not shift after the report is published.
  • Saved weeks are kept for 400 days.

Behavior and limits

  • Cost: 0 credits.
  • Rate limit: 60 requests per minute per key.
  • Dates: week_start must be a Monday. 2026-09-29 (a Tuesday) is rejected.
  • Rank moves need alerts on. queries_up, queries_down and the rank.moves_detected events come from the daily rank-change detection, which runs only for websites with rank-change alerts enabled. Without that, they stay at 0. See the alert settings.
  • No data: a new website returns a valid report with queries_up and queries_down at 0, an empty events array and, without Search Console, null clicks.
  • Scope: only your own workspace's websites. A site_id from another workspace returns the same 404 as a site that does not exist.

Errors

HTTPCodeWhen
400invalid_client_report_inputsite_id is missing, or week_start is not a Monday in YYYY-MM-DD form or is in the future.
401invalid_api_keyMissing, invalid or revoked API key.
404site_not_foundThe website does not exist in your account.
429rate_limitedMore than 60 requests in a minute.

See Error codes.

On this page