Loading...

Analytics

Every search made through SearchStack is counted; send a click when a visitor picks a result, then read what people searched for, what found nothing and what they clicked.

  • The console shows the same report under Insights → Analytics.
  • Clicks also feed reranker lift, user generated suggestions and related-result ranking (list-route clicks only).
  • require_click reads clicks sent to the list route, including ones carrying a group search’s query_id. Group-route clicks are not read.
Record a click
RouteUse for
POST /search/analytics/click/list/{account-name}/{list-name}A hit from a list search.
POST /search/analytics/click/group/{account-name}/{group-name}A hit from a group search.
Body fieldWhat to send
query_idThe query_id from the search response. Not checked against a stored search. Suggest and related responses carry none.
result_idThe clicked hit’s name — not its id.
list_nameGroup clicks: the hit’s list_name. Without it the click counts toward click-through but not reranker lift. A list outside the group is a 400. Ignored on list clicks.
  • Answers 204 with no body.
  • An empty or all-space query_id or result_id, or a list or group that doesn’t exist, also gets a 204, but nothing is recorded. Omitting either field is a 400.
  • Needs search-result:read on the list or group.
  • A click sent to the list route counts in that list’s report, even one carrying a group search’s query_id, and is then not in the group’s report. require_click reads only list-route clicks, so a group site choosing it moves those clicks into the list report.
  • Every API key on an account shares one per-minute search rate limit, and clicks spend it too, so one click per search uses it twice as fast. Over it, clicks and searches both get a 429 with Retry-After (seconds) and a problem body naming the same wait.
Read a report
RouteReport for
GET /analytics/list/{account-name}/{list-name}?from=&to=One list.
GET /analytics/group/{account-name}/{group-name}?from=&to=One group.
  • from and to are UTC dates (yyyy-MM-dd), both inclusive.
  • to defaults to today and is capped at today.
  • from defaults to 29 days before to (a 30-day range). A from after to becomes to.
  • A range is at most 366 days; an earlier from is raised to fit. The response’s from and to show the range used.
  • A list that does not exist is a 404.
Response fields
FieldMeaning
account, scope, targetThe account, list or group, and its name.
from, toThe range used, after defaults and caps.
total_searchesSearches in the range.
zero_result_searchesSearches that ran and returned nothing.
total_clicksClicks recorded in the range.
click_through_ratetotal_clicks ÷ total_searches as a fraction (0.25 = 25%); 0 when there were no searches. Can pass 1 when searches get several clicks.
top_searchesUp to 20 {term, count}, most frequent first.
top_zero_result_searchesUp to 20 terms that found nothing.
dailyOne point per UTC day (date, searches, zero_result_searches, clicks), zero-filled.
reranked_searchesSearches a reranker ran on.
reranker_top_changed_rateFraction (0–1) of reranked searches whose top hit changed.
reranker_mean_displacementMean places the results shown moved up. A reorder within the page nets 0, so this measures results pulled up from further down. The console calls it Pulled up from below.
reranker_click_liftMean positions the reranker moved clicked results up; positive is better, 0 with no sample.
reranker_lift_sample_sizeClicks behind reranker_click_lift.
catching_uptrue while older searches are still being counted, a raw read was throttled, or a busy hour ran past the request’s time — read again shortly.
What is counted
  • Each search that ran counts once: list and group searches, image searches and Ask.
  • Suggest (search-as-you-type) and related-result calls are not counted.
  • Refused, failed and cancelled searches are not counted.
  • Later pages of a search (skip above 0) are not counted as searches or terms, so a page past the end never adds a zero-result term.
  • Search text counts as a term. Terms are compared ignoring case and cut to 100 characters; each day keeps its top 500.
  • A group search counts in the group’s report only. A list report leaves out searches that came through a group.
  • Eval (including Ask evals), judge and watch searches are not counted.
  • A list on an attached index counts only searches made through SearchStack; searches your app sends straight to Azure AI Search are not seen. Image search and related results there are refused with a 400 and not counted.
  • Days counted before these rules shipped can also include suggest and related calls, later pages, and refused, failed or cancelled searches.
  • Counting is best-effort: events can be lost when a server crashes or restarts, or when analytics storage is down for more than 10 minutes.
Permissions
  • Reading a list report needs analytics:read on the list or the account.
  • A group report needs it on the account or on every list in the group today. The report still covers the group’s whole history, including searches made while it held other lists.
  • A refused list report names the permission needed (analytics:read on the account or this list); so does a refused click (search-result:read).
  • A 503 means analytics storage is unavailable or slow; try again shortly (no Retry-After). A group report whose account read fails is also a 503, for every caller.
  • A missing group is a 404 for an account-wide key and a 403 for any other key.
  • The default Search and read API key can record clicks but not read reports; Read all can do both.
Retention
  • Raw search and click events are kept; no automatic purge runs.
  • Deleting a list, group or account deletes its analytics.
  • List and group deletes purge again about 15 minutes later, catching events still being written when the delete ran.
MCP tools
ToolDoes
analytics_get_listReads a list report.
analytics_get_groupReads a group report.
record_list_clickRecords a click on a list hit.
record_group_clickRecords a click on a group hit.
Top