Documentation » Tool Reference
Tool Reference
Every tool the Kafkai MCP server exposes, grouped by what it does. Tool names are stable identifiers — your agent sees exactly these names.
To see the tools in use before reading them one by one, start with the Example Prompts page; each prompt there lists the tools the agent calls behind it.
Conventions
- Responses are JSON. Every tool returns a JSON document.
Successful responses include a
next_step_suggestionfield: advice the server computes for the agent's next move (which tool to call, or what to search the web for). Agents follow these hints without special prompting. - Usage reporting. Metered tools append a
_usageobject showing what the call cost and your remaining balance. See Credits and Billing. - Limits.
limitarguments are capped server-side (100 for keyword lists, 50 for clusters). Asking for more returns the cap, not an error. Lists longer than the cap are read a page at a time — see Reading a long list below. - Identifiers. Projects are addressed by
project_id(fromkafkai_list_projects), competitors bycompetitor_domain(fromkafkai_list_competitors), and publishing destinations bydestination_id(fromkafkai_list_publishing_destinations).
Reading a long list
A research run can return far more keywords than one call should carry, so the list tools return one page at a time. Every paged response says where its page sits:
count— rows in this response.total_matching— rows in the whole list the page came from.offset— rows skipped to reach this page.
To read the next page, call the same tool again with offset raised
by your limit. While rows remain, next_step_suggestion names the
exact offset to use, so an agent walks a long list without being told
how. A count smaller than your limit means the page is the last
one. An offset past the end returns no rows and reports how many
there are, rather than failing.
The keyword, cluster, backlink, Search Console and analytics list
tools all take offset. The tools that return one short list —
projects, competitors, publishing destinations — do not.
Each page is a separate call carrying its own flat call fee, so one call of 100 rows costs less than five calls of 20. Read in the largest pages a tool allows, and stop once you have what you need. See Credits and Billing.
Projects and competitors
kafkai_list_projects
Lists your projects with id, site URL, status, location, and
keyword and competitor counts. This is the usual first
call — later tools need the project_id it returns.
Arguments: none.
kafkai_get_project_summary
A full overview of one project: site metadata, niche, location,
keyword counts per 4C strategy and for your own ranking baseline,
the competitor list, and three blocks that say what data exists —
authority (your site's strength next to each competitor's),
backlinks (whether backlink data exists for your site and each
competitor, with the whole-profile totals, and a next_step_suggestion
naming which backlink tool to call) and search_console (whether
Kafkai can read your site's Google Search Console property, whether
the domain is verified for your account (domain_verified) and the
window its data covers, with a next_step_suggestion that names the
two Search Console tools or the step still missing: verifying the
domain, or granting access). The
response also names a recommended_strategy — the strategy with the
most keyword opportunities — with the reason. last_research is the
project's latest research run — a full update, or the research an added
competitor bought: pending while it is still running, then its verdict
(success, partial or failed) with the reason when something failed.
Arguments:
project_id— the project to summarise.
kafkai_list_competitors
Lists the competitor sites tracked in a project, with each
competitor's keyword count and research status. A competitor whose
research failed reads failed, with the reason in error; its keyword
lists are incomplete, and the response's next_step_suggestion says how
to retry — kafkai_update_keywords researches every domain again, or
remove the competitor and add it again for the competitor fee. The
response highlights the top_competitor by keyword count and carries
last_research, the project's latest research run.
Arguments:
project_id
kafkai_find_competitors
Finds the sites a project's site competes with in search, from the
keywords the site actually ranks for — not from a guess about its
homepage. Kafkai takes the domains that rank for the same keywords in
the project's country (the 1,000 largest sites on the web excluded),
scores each by how much of the two keyword footprints overlap, sizes
it against your site with the same winnability rule the 4C tools use,
and drops review sites, marketplaces, listicle publishers and
unrelated domains. Competitors the project already tracks are flagged
already_tracked, so the list reads as "who else".
Each row carries domain, relationship (direct, adjacent, or
unknown when it could not be judged), winnability, rank
(0–1000), intersections (the keywords you share), overlap (that
count as a share of both footprints, 0–1), avg_position, etv,
keywords_count, sample_keywords and already_tracked.
filtered_out counts the domains the judge dropped, and site gives
your own keyword count, traffic estimate and rank. Rows are ordered
direct competitors first, then winnable before avoid, then by
overlap.
Two things to know when reading the rows:
- A site Google does not rank for anything yet is answered from the
searches its customers make (
methodiscustomer_searches, andseed_keywordslists them): who ranks on page one for those, smallest sites first.overlap,etvandkeywords_countare empty on that path andwinnabilityisunknown. - Kafkai returns the candidates and the evidence; which of them
matter is your agent's reading. Adding one is a separate, priced
step:
kafkai_add_competitor.
Carries its own call fee, higher than a plain read, because the tool buys fresh competitor, authority and judgement data rather than returning what the project already holds; the per-row amount is the same as every other read. The answer is cached for a day, so a repeat call returns the same list. See Credits and Billing.
Arguments:
project_idlimit— max competitors to return (default 10, max 20).
kafkai_get_competitor_analysis
A focused analysis of one competitor: its brand description, the keywords it ranks for that you do not (Catch-up), and the keywords you both rank for (Compete). Higher base cost than a plain list.
Every keyword carries competitor_previous_rank and
competitor_rank_change (and our_previous_rank and
our_rank_change on Compete rows): the move since Kafkai's previous
measurement.
Arguments:
project_idcompetitor_domain— fromkafkai_list_competitors.include_history— set to true to include each keyword's dated positions:competitor_historyfor this competitor,our_historywhere you rank too.
Keyword research — the 4C strategies
The four strategy tools share their shape: each returns keyword
objects with search volume, keyword difficulty, CPC, ranks, the
ranking page's SERP title and description where relevant, tags, and
freshness timestamps (first_seen, last_updated). A recommended
subset highlights the strongest starting keywords by volume and
difficulty.
Every rank is dated. Each keyword also carries the move of each side
since Kafkai's previous measurement: our_previous_rank and
our_rank_change where you rank, competitor_previous_rank and
competitor_rank_change where the competitor does. A positive change
means the position moved up. Catch-up, Consolidate and Compete also
accept include_history: set it and each keyword carries the dated
positions Kafkai has recorded for every side that ranks
(our_history, competitor_history), oldest first, with unchanged
positions collapsed. For "what moved over the last three months", use
kafkai_get_ranking_changes below instead.
Catch-up, Consolidate and Compete each measure your site against a
competitor, so they stay empty until the project has at least one.
Complement does not — it works from your own topics, with or without
competitors. To see what your site ranks for when no competitor is
registered, use kafkai_get_ranked_keywords below.
All four take the same arguments:
project_idlimit— max keywords to return (default 20, max 100).offset— rows to skip, for paging (default 0). The response'snext_step_suggestionnames the next offset while more rows remain, andtotal_matchingsays how many rows there are in all.include_history— Catch-up, Consolidate and Compete only. Set to true to include the dated positions of each side that ranks.
kafkai_get_catchup_keywords
Catch-up: keywords competitors rank for that you do not — your content gaps. Each keyword shows which competitor ranks and with what title, so the agent knows exactly what page it is up against.
kafkai_get_consolidate_keywords
Consolidate: keywords you already rank for that competitors do not — the territory that is working and worth strengthening.
kafkai_get_compete_keywords
Compete: keywords where both you and a competitor rank — head-to-head battles. Both ranks are returned, so the agent can pick fights where the gap is small.
kafkai_get_complement_keywords
Complement: related keywords that neither you nor your competitors
target yet — what to add next to the topic map. Each keyword is
returned once, however many of your topics suggested it, so limit
counts distinct keywords.
kafkai_get_keyword_clusters
Semantic clusters: groups of related keywords that one comprehensive article can cover together. Each cluster carries its average search volume, difficulty, and CPC, plus its member keywords. The response recommends the highest-volume cluster.
Arguments:
project_idlimit— max clusters (default 10, max 50).offset— clusters to skip, for paging (default 0). The response'snext_step_suggestionnames the next offset while more clusters remain, andtotal_matchingsays how many there are in all.
Your own rankings
kafkai_get_ranked_keywords
Every keyword your site already ranks for, and how each position has moved. This is not one of the 4C strategies: those compare your site against a competitor, while this one reads your own positions directly. It works on a project with no competitors at all, which makes it the first useful call on a brand-new project.
Each keyword returns your current position, the previous one, the
change since the last measurement, whether the keyword is newly
ranking, plus search volume, difficulty, CPC and the page that ranks.
A progress object tallies what improved, declined, stayed flat and
is new, and how many keywords sit in the top 3 and top 10.
Set include_history and each keyword also carries the positions
Kafkai has recorded over time, oldest first — enough to chart a trend.
Unchanged positions are collapsed, so you get the moves rather than
one point per update.
Three things to know when reading the numbers:
- A keyword here may also appear under Consolidate or Compete. This is your whole ranking picture, not a slice of it.
progresscounts only the keywords this call returned, not the whole project. The project-wide figure istotal_ranked_keywords.- On the first call for a new project there is no earlier Kafkai measurement to compare against, so the change is counted from the position first seen.
Positions refresh when you run kafkai_update_keywords — that is what
adds the next point to each keyword's history.
Arguments:
project_idlimit— max keywords to return (default 20, max 100).offset— rows to skip, for paging (default 0). The response'snext_step_suggestionnames the next offset while more rows remain, andtotal_matchingsays how many rows there are in all.include_history— set to true to include past positions for each keyword.
Ranking changes over time
kafkai_get_ranking_changes
Which keywords gained or lost positions over a period — for your own site, one competitor, or every competitor at once. Every rank Kafkai measures is dated, so the tool compares each keyword's position at the start of the period with its position now and sorts the biggest moves first. It answers "what moved in the last three months", "where is this competitor slipping", "which keywords did I lose", and "what are my opportunities from competitors' falling rankings".
Each keyword returns its movement — improved, declined, new
(ranks now, did not at the period start) or lost (ranked at the
period start, does not now) — with current_rank and measured_at,
baseline_rank and baseline_measured_at, rank_change (positive
when the position moved up), first_seen, search volume, difficulty,
CPC and the ranking page. Competitor reports add competitor_domain
and our_rank: where your site sits on the same keyword right now. A
competitor sliding on a keyword you sit close behind, or do not rank
for yet, is the opening to write for.
A summary counts what improved, declined, stayed unchanged, is new
and is lost across every keyword measured for the site, not just the
rows returned. Unchanged keywords are counted there and left out of
the list.
Three things to know when reading the numbers:
- Updates run on demand, so there is no measurement for "exactly 90
days ago". The baseline is the latest measurement at or before the
period start, and
baseline_measured_atsays when that was. - When tracking began inside the period (
period.tracked_since), the first measurement stands in for the period start, and the keywords from that first run are not "new". - Rows are merged per keyword, so a keyword that moved between strategies keeps one continuous history.
Positions refresh when you run kafkai_update_keywords — that is what
adds the next dated measurement.
Arguments:
project_idcompetitor_domain— empty for your own site, a competitor's domain (fromkafkai_list_competitors) for that competitor, orallfor every competitor merged into one list (the response then also carriescompetitor_domainsand aby_competitorbreakdown).days— length of the period in days (default 90, max 365).movement—all(default; every kind of move but unchanged),improved,declined,neworlost.limit— max keywords to return (default 20, max 100).offset— rows to skip, for paging (default 0).total_matchingcounts the rows that matchmovement;summarystill counts the whole site.
Backlinks
Who links to your site and to each competitor, how strong those sites are, when each link was last seen, and how many links each site gained and lost over time. Kafkai returns the data; the reading — what the linking sites have in common, which lost link is worth chasing — is your agent's.
Kafkai fetches backlinks as part of every research run: for the site
and each competitor when a project is created, for the new competitor
when one is added, and for every site on kafkai_update_keywords. The
three read tools below answer from that snapshot; kafkai_update_backlinks
refreshes backlinks alone, without re-buying keyword data. Every
response says when the snapshot was taken (as_of), and a site that
has not been fetched yet says so instead of returning empty rows.
kafkai_get_backlinks
The sites linking to your site or to one competitor — one row per
referring domain, its strongest link, strongest first. It answers "who
links to competitor X", "how strong are the sites linking to me", and,
with status set to lost, "which links did competitor X lose that I
could win": every lost row names a site that once linked to a page like
target_page and stopped, with last_seen dating the loss.
Each row carries referring_domain, referring_page, target_page,
page_title, anchor, link_type, dofollow, link_rank,
referring_page_rank and referring_domain_rank (0–1000, higher is
stronger), spam_score, platform_types, country, first_seen,
last_seen, is_lost, is_new, is_broken and links_from_domain.
Two things to know when reading the numbers:
profileholds the whole link profile:domain_rank,backlinks_total,referring_domains_total, the nofollow and broken counts, and the link type, platform, country and TLD mixes. Quote those totals for the size of the profile.- The rows are a sample of it. Kafkai stores the strongest link from up
to 1,000 referring domains, and the strongest links lost within the
last year.
coveragesays how many rows are stored and whether the live sample is complete, so an agent can say "the strongest 1,000 of 18,452" rather than imply it saw everything.
Arguments:
project_idcompetitor_domain— empty for your own site, or a competitor's domain (fromkafkai_list_competitors). One site per call.status—live(default),lost(links that disappeared within the last year) orall.limit— max rows to return (default 20, max 100).offset— rows to skip, for paging (default 0). The response'snext_step_suggestionnames the next offset while more rows remain.
kafkai_get_backlink_changes
How many backlinks and referring domains a site gained and lost over a period — your own site, one competitor, or every site in the project side by side. Kafkai keeps a daily new/lost count for each site (a year of history from the first fetch), so the period is summed from that, with a month-by-month breakdown. It answers "how many links did competitor X win in the last three months", "is their link building accelerating", and "am I keeping pace".
Each site row carries status and as_of, totals_now (backlinks,
referring_domains, domain_rank), period_totals (new_backlinks,
lost_backlinks, net_backlinks, new_referring_domains,
lost_referring_domains, net_referring_domains), by_month, and
data_from / data_to — the days the stored history actually covers.
A site whose status is not ready has no counts yet.
Arguments:
project_idcompetitor_domain— empty for your own site, a competitor's domain (fromkafkai_list_competitors), orallfor your site and every competitor, one row each.days— length of the period in days (default 90, max 365).
kafkai_get_link_gaps
The sites that link to two or more of your competitors but not to you
— the link gap. One row per referring domain, strongest first, with the
link it gives each competitor (referring_page, target_page,
anchor, dofollow, link_rank, last_seen). A site that already
links to several competitors covers your topic and accepts links to
sites like yours, so it is the first place to ask for one. Kafkai
returns the rows; which sites to approach, and what to offer them, is
your agent's reading.
Each row carries referring_domain, competitor_count,
referring_domain_rank (0–1000, higher is stronger), spam_score,
country and links. competitors_with_data and
competitors_without_data say which competitors the answer covers.
Two things to know when reading the rows:
- It needs backlink data for your own site — that is how "not linking
to you" is decided — and for at least
min_competitorscompetitors. Until then the response names the sites still missing and how to fetch them. - "Not linking to you" is judged against the stored sample of your live
links (
own_site_coverage, the same shape ascoverageabove), so a site outside that sample can appear in the list although it links to you.
Arguments:
project_idmin_competitors— how many competitors a site must link to before it counts as a gap (default 2, minimum 1). Pass1to see every site that links to any competitor but not to you.limit— max rows to return (default 20, max 100).offset— rows to skip, for paging (default 0). The response'snext_step_suggestionnames the next offset while more rows remain.
kafkai_update_backlinks
Fetches fresh backlink data for your site and every competitor in a project: the linking sites and their strength, the links lost in the last year with the date each was last seen, and a year of daily gained/lost counts. This is what the three read tools above answer from.
Backlinks are already fetched by kafkai_create_project,
kafkai_add_competitor and kafkai_update_keywords. Use this tool to
refresh them without re-buying keyword data — for a project created
before backlinks existed, after a failed fetch, or when a day-old
snapshot is not fresh enough.
The fetch runs in the background and takes about a minute per site. A
site fetched within the last day is skipped, and a site whose fetch is
still running is not fetched twice, so calling this twice in a row costs
nothing extra. The response lists the sites it is fetching now
(domains), the ones it skipped (skipped_fresh) and the ones already
running (in_flight).
Charges a backlinks-only fee once per site actually fetched — smaller than a full update, because no keyword data is bought; see Credits and Billing.
Arguments:
project_id
Domain verification
Kafkai serves a site's own private data — its Search Console queries,
pages and clicks today, other sources later — only to an account that
has proved it controls the domain. The proof is one DNS TXT record on
the project's registered (apex) domain — a project on blog.example.com
is proved at example.com, and example.co.jp is proved at
example.co.jp (the Public Suffix List decides what "registered" means,
so a two-label country suffix is kept whole). One record opens every
subdomain project for your account. The code is unique to your account
and that domain. Two accounts can both verify one domain — a site owner
and their agency, say — each with their own record. Both tools are free.
- Call
kafkai_verify_domainwith theproject_id. The response'sdns_recordgives the record to add:type(TXT),name(the domain) andvalue(kafkai-verification=followed by the code). - Add that record at the DNS provider for the domain.
- Call
kafkai_check_domain_verification. Kafkai looks the record up; when it is there,statusbecomesverified. DNS changes usually show within minutes but can take up to 48 hours, so call again later if the record was not found yet.
Kafkai re-checks verified domains periodically. A record that is later removed stops the data until it is put back; the code stays the same, so there is nothing to redo but the record.
The same record, check button and status are on the Domains page of your account, one entry per domain — use it when you would rather copy the record from a browser than through the agent. Both paths share one code per domain.
kafkai_verify_domain
Starts verifying the project's domain, or returns the existing code, with the DNS record to add. Calling it again never changes the code.
Arguments:
project_id
The response carries domain (the project's registered domain, where
the record goes), status (pending or verified), dns_record
(type, name, value), verified_at, last_checked, last_error
and a next_step_suggestion.
kafkai_check_domain_verification
Looks the record up now and reports the result in the same shape as
kafkai_verify_domain. A missing record keeps status at pending
and says in last_error what was looked for. A lookup that got no
answer (a timeout) changes nothing; try again in a few minutes. Calling
this before kafkai_verify_domain is fine: the code is created and the
record to add is in the answer.
Arguments:
project_id
Search Console
Your own Google Search Console data, read by two tools. Kafkai's ranking data is a sample of search results; Search Console is what Google actually recorded for your site — every query it appeared for, with real clicks, impressions, click-through rate and average position. Together they answer what the rankings alone cannot: what people searched, which pages they clicked, and what changed.
Both tools describe one period: the latest 28-day window Kafkai has
stored, compared with the 28 days before it. Every row and the
property-wide totals carry clicks_change, impressions_change and
position_change against that prior window. position_change is
positive when your site moved up the page — the same sign the ranking
tools use.
Two steps stand between a project and its data. While
search_console.status is not_connected, both tools name the first
one still missing in their next_step_suggestion, so your agent can
pass it on to you.
- Verify the domain (see Domain verification above). Until then Kafkai serves nothing for the domain, not even whether a property exists.
- Grant Kafkai read access to the property. This is one step in Search
Console, and shares nothing but an email address: open the property
in Google Search Console,
go to Settings > Users and permissions > Add user, enter
the Kafkai reader address and choose the Restricted permission
level. The address is in the
next_step_suggestiononce the domain is verified. For a walkthrough with screenshots, see Connect Google Search Console.
Kafkai picks the property up at the next research run
(kafkai_update_keywords), backfills 16 months of history, and
refreshes it at the end of every later run. Until the first sync
finishes the status is syncing.
Two things to know when reading the numbers, both Google's doing:
- Google leaves out the queries it anonymises, so the query rows add
up to less than the property's true totals.
totalsare exact, andcoveragereports the impressions the query rows carry (visible_impressions), the exact total (total_impressions) and the share between them (visible_impressions_share). The share is measured over the rows the call returns, so it describes what you can actually see. - Google Discover reports pages and totals but no queries, so
search_type='discover'works with the pages and trend views only.
kafkai_get_search_console_data
The queries your site appears for, the pages that earn the traffic, or the daily totals — three views of one period.
view='queries'(default): one row per search query in the current window —query,clicks,impressions,ctr,position, the prior window's numbers underprior, and the three change fields.view='pages': one row per page of your site, summed from Google's daily page figures, which are exact.view='trend': one row per day, oldest first, taken from the recent end of the prior and current windows — enough to see the day traffic turned. Passlimit=100for the whole series.
Every response carries search_console (property, status,
domain_verified),
window, prior_window and totals (current, prior and the
change fields). Use it next to kafkai_get_ranked_keywords: a query
here that the ranking data does not show is a real search Kafkai's
sample missed.
Arguments:
project_idview—queries(default),pagesortrend.order_by— for the queries view:impressions(default),clicksorposition(best first). Pages are always ordered by impressions.contains— only queries (or page URLs) containing this text, case-insensitive. The trend view has neither, so it ignores this and does not echo it back.search_type—web(default) ordiscover.limit— max rows to return (default 20, max 100). For the trend view it is a number of days counted back from the most recent, solimit=100returns the whole series in one call.total_matchingalways says how many days the two windows hold.offset— rows to skip, for paging (default 0). The trend view counts back from the most recent day, sooffsetsteps further into the past. The response'snext_step_suggestionnames the next offset while more rows remain.
kafkai_get_search_console_insights
What to work on first, computed by Kafkai from your Search Console
data. Five kinds of flag, each a query or page with the numbers behind
it in evidence and a score to rank by within its kind:
striking_distance— queries ranking just off page one (positions 8–20 by default) with real impressions. Score: the extra clicks expected from reaching position 5.ctr_gap— queries whose click-through rate is far below what their position normally earns on your site: usually a title or snippet problem, not a ranking problem. Score: clicks lost.cannibalisation— one query split across two or more of your pages, each taking a real share of the impressions. Score: the impressions at stake.new_query— queries your site newly appears for, compared with the prior window. Score: impressions.decay— pages whose clicks dropped hard against the prior window, computed for web search and Google Discover separately. Score: clicks lost.
The response's definitions states each rule with the thresholds in
force, and counts says how many flags of each kind exist. Scores
compare within a kind only — the units differ. Kafkai computes the
flags; deciding what to change is your agent's reading of the
evidence, with kafkai_get_search_console_data for the surrounding
rows.
Arguments:
project_idinsight_type—all(default) or one ofstriking_distance,ctr_gap,cannibalisation,new_query,decay. Withall,limitandoffsetapply per kind.limit— max rows to return per kind (default 20, max 100).offset— rows to skip per kind, for paging (default 0).
Analytics
Your own traffic analytics, read by one tool. Search Console covers the search angle — what people searched for and what Google recorded. Analytics covers the whole visit: how many people came, which pages they opened, where they came from, and what they used to browse. It answers what the search data cannot: how much traffic the site gets overall, and what visitors do once they arrive.
Two steps stand between a project and its data, and the analytics.status
block (not_verified, not_configured, unavailable, ready) names
the one still missing in next_step_suggestion:
- Verify the domain (see Domain verification above). Until then Kafkai serves nothing for the domain, not even whether analytics tracking exists for it.
- Ask Kafkai support to set up tracking for the site. Kafkai sets it up on its own analytics instance; there is no customer-side setup, and nothing to connect afterwards: the first call finds the site automatically and keeps it. A site set up a moment ago can take up to ten minutes to appear. A project on a subdomain uses the site of its registered domain when it has none of its own.
unavailable means Kafkai could not reach its analytics service on
this call; it says nothing about whether tracking exists. Try again in
a minute.
Unlike Search Console there is nothing to wait for: the data is read
live at call time, so once the status is ready the next call returns
what the site holds right now.
kafkai_get_analytics_data
Traffic, pages, referrers, visitor location and devices, in 21
reports. By default it covers the last 30 days; pass
period='day' and date='last30' for a daily time series.
Every response carries analytics (status, domain_verified,
id_site, site_url), the report, a short description of the
report, the period and date in force, count and rows. While
more rows remain, next_step_suggestion names the offset for the
next page.
Arguments:
project_idreport— one of:summary(default),pages,entry_pages,exit_pages,page_titles,outlinks,downloads,referrers,search_engines,keywords,social,websites,campaigns,countries,regions,cities,device_types,browsers,browser_versions,operating_systems,screen_resolutions.summaryreturns one metrics row — visits, unique visitors, actions, bounce rate and average visit duration; the rest return a list of rows.period—day,week,month,yearorrange. Empty defaults torange.date— empty defaults to the last 30 days. Examples:today,last30,2024-01-01,2024-01-31(forperiod='range').segment— optional segment definition to filter visits.limit— max rows to return for list reports (default 20, max 100). Ignored bysummary.offset— rows to skip, for paging (default 0).
kafkai_get_ga_analytics_data
The customer's own Google Analytics 4 data: traffic, pages, landing pages, channels, source/medium, countries, cities, devices, browsers, operating systems and key events. Read live from the customer's GA4 property — not stored, so there is nothing to sync or wait for once access is granted.
Same domain-verification gate as Search Console and analytics. The
ga_analytics.status block (not_verified, not_connected,
ambiguous, unavailable, ready) names the step still missing in
next_step_suggestion:
- Verify the domain (see Domain verification above).
- In Google Analytics, go to Admin › Property access management › Add users, enter the Kafkai reader address and pick the Viewer role. Kafkai finds the property on the next tool call — no research run needed.
ambiguous means more than one GA4 property claims the site; contact
Kafkai support with the property id to use.
Every response carries ga_analytics (status, domain_verified,
property_id, property_name, stream_uri), the report, a short
description, start_date and end_date in force, count, total,
subject_to_thresholding and rows. GA4 can take 24-48 hours to
process data, and may hide small rows for privacy —
subject_to_thresholding says when that happened. Numbers will not
match Search Console: GA4 counts sessions from all sources, Search
Console counts clicks from Google Search.
Arguments:
project_idreport— one of:summary(default),daily,pages,landing_pages,channels,source_medium,organic_landing_pages,countries,cities,devices,browsers,operating_systems,key_events.summaryreturns one metrics row; the rest return a list of rows.start_date— ISO date (2026-08-01) or GA4 relative date (30daysAgo,yesterday,today). Empty defaults to 30daysAgo.end_date— ISO date or GA4 relative date. Empty defaults to yesterday.limit— max rows to return (default 20, max 100). Ignored bysummary.offset— rows to skip, for paging (default 0).
SERP intelligence
kafkai_get_keyword_serp_data
Everything known about one keyword in a project: who ranks (domains,
SERP titles, descriptions, URL types), your rank, competitor ranks,
rank changes, search volume, difficulty, CPC, and tags. The response
includes a ranking_context interpretation — for example, "competitor
ranks #3, you don't rank — write content to capture this demand".
If the exact keyword is not found, near matches are returned instead.
Higher base cost.
Arguments:
project_idkeyword— the exact keyword to look up (falls back to a contains-match).
Project management
These tools change data. Research runs asynchronously — queue it,
keep working, and check back with kafkai_get_project_summary.
kafkai_create_project
Creates a project for a site, adds any competitors you give, and queues the full keyword research — including the backlinks of the site and of each competitor (see Backlinks). Priced per site researched: a base fee for your site plus a competitor fee for each competitor you give; see Credits and Billing.
Arguments:
site_url— the site to analyse, for examplehttps://example.com. Required.site_name— a display name; defaults to the URL.description— a short description of the site.location_code— the country whose search results the project targets. Required, with no default. The code is 2 followed by the country's ISO 3166-1 numeric code: Japan is2392, Malaysia2458, the United States2840. Call the tool without it and it fails for free, listing every market you can pick.competitors_url— a list of competitor site URLs. Optional.
Competitors are optional, and you can add them later with
kafkai_add_competitor. Without them, Catch-up, Consolidate and
Compete stay empty — each needs a competitor to compare against — but
Kafkai still collects your own ranking baseline and Complement
keywords, so a project starts useful with nothing but a domain and a
country.
A project is locked to one country. Research for the wrong country costs the same and tells you nothing, which is why Kafkai asks instead of guessing.
kafkai_add_competitor
Adds one competitor to an existing project and fetches only that competitor's data — its keywords and its backlinks. Existing competitors and the site itself are not re-fetched, so this is much cheaper than a full update: it charges the competitor fee once.
The research runs in the background and is logged like a full update;
the response carries its update_log_id. Check kafkai_list_competitors
a few minutes later: the competitor's status reads ready when its
data is in, or failed with the reason in error. While the research
runs, kafkai_update_keywords and the delete tools are refused for the
project.
Arguments:
project_idcompetitor_url
kafkai_delete_competitor
Removes one competitor from a project, together with every keyword Kafkai collected for it and that keyword's ranking history. Use it when a competitor was added by mistake and its unrelated keywords are polluting the Catch-up, Consolidate and Compete lists. Free.
The deletion is permanent, so the tool runs in two steps:
- Call it without
confirmation_token. Nothing is deleted. The response lists what would be removed (keywords per strategy, research sessions, ranking history) and what would be kept, and includes aconfirmation_tokenvalid for 15 minutes. - Your agent shows you that summary and asks you to confirm. Only
then does it call the tool again with the same
project_idandcompetitor_domainplus the token. The competitor is marked for deletion and its data is removed in the background; check withkafkai_list_competitorsa few minutes later.
A token is bound to one competitor and one account. Reused for a different competitor, or after it expires, it is refused and nothing happens. The deletion is refused while a keyword update for the project is running; wait for it to finish and ask again.
Arguments:
project_idcompetitor_domain— fromkafkai_list_competitors; a full URL is accepted too.confirmation_token— empty for the preview; the token from the preview to run the deletion.
kafkai_update_keywords
Queues a fresh ranking update for the whole project: all strategies
and your own ranking baseline are re-fetched, ranks on existing
keywords refresh, and keywords that dropped out are marked lost. This
is what adds the next point to each keyword's position history, so run
it before asking kafkai_get_ranked_keywords or
kafkai_get_ranking_changes what moved. The backlinks of the site and
of every competitor are refreshed in the same run (a site fetched within
the last day is reused). Priced like creation: the base fee for your
site plus the competitor fee for every competitor in the project.
Only one research run per project happens at a time; a second request while one is running — including the research an added competitor triggers — is refused. A project whose deletion you have confirmed cannot be updated either; that request is refused before anything is charged. Updates run on demand — Kafkai does not re-fetch rankings on its own schedule.
Arguments:
project_id
kafkai_delete_project
Deletes a project and everything in it: competitors, every keyword with its ranking history, and research sessions. Use it for a project you no longer need, or one that was set up with the wrong site. Free.
The deletion is permanent, so the tool runs in two steps:
- Call it without
confirmation_token. Nothing is deleted. The response lists what would be removed (competitors, keywords per strategy, research sessions) and what is not touched, and includes aconfirmation_tokenvalid for 15 minutes. - Your agent shows you that summary and asks you to confirm. Only
then does it call the tool again with the same
project_idplus the token. The project is marked as deleting and its data is removed in the background; check withkafkai_list_projectsa few minutes later.
A token is bound to one project and one account. Reused for a different project, or after it expires, it is refused and nothing happens. Posts already published to your own site stay live, and publishing destinations and publication records belong to your account and are kept. The deletion is refused while a keyword update for the project is running; wait for it to finish and ask again.
Arguments:
project_idconfirmation_token— empty for the preview; the token from the preview to run the deletion.
Publishing
Kafkai does not write articles. Your agent writes the piece from the data above, then hands the finished text to Kafkai to publish. Kafkai keeps a snapshot of exactly what it sent — title, body, language — as the publication record; it holds no other copy of the article.
kafkai_list_publishing_destinations
Lists the active publishing destinations on your account — WordPress
sites and webhooks — with each one's destination_id, name, type and
URL. Destinations belong to the account, not to a project.
Arguments: none.
kafkai_add_publishing_destination
Adds a destination. For WordPress, pass the site URL and an application password; for a webhook, the endpoint URL and its credentials. The credentials are stored encrypted and never returned.
Arguments:
name— a label for the destination (unique on your account).destination_type—wordpress(default) orwebhook.url— the site or endpoint URL.auth_type—basic(default),api_key,beareroroauth2.credentials— the login details for that auth type.
kafkai_delete_publishing_destination
Removes a destination. Posts already published through it stay where they are, and their publication records are kept. Free.
Arguments:
destination_id
kafkai_publish_article
Publishes text your agent wrote to one destination and returns where
the post went (external_url). Pass the body as HTML in content, or
as Markdown in content_markdown — when content is empty, the
Markdown is rendered to HTML for you, and webhook destinations also
receive the Markdown as written. The post goes up as a draft unless you
ask for it to go live, so you can review it on your own site first.
To update an existing post instead of creating a new one, pass its
external_id (returned by a previous publish call). This edits the
existing post on the destination rather than creating a duplicate.
Arguments:
project_id— the project the article was written for; its market sets the default language.destination_id— fromkafkai_list_publishing_destinations.titlecontent— the body as HTML. Required unlesscontent_markdownis given.content_markdown— the body as Markdown.language— e.g.enorja. Defaults to the project's market language.post_status—draft(default) orlive.categories— WordPress category names, e.g.["Education", "Coffee"]. Categories that don't exist yet are created automatically. Ignored for webhook destinations (forwarded as-is).slug— the URL slug for the post, e.g.my-first-article. Ignored for webhook destinations (forwarded as-is).external_id— the ID of an existing post on the destination to update instead of creating a new one. Use theexternal_idreturned by a previous publish call. When omitted, a new post is created.
Credits
kafkai_get_credit_balance
Your current balance, lifetime totals, and the last ten transactions with per-call cost breakdowns. Free — checking your balance never costs credits.
Credits are valid for 90 days from the day they are added, and the
oldest are spent first. expiring lists every batch still unused with
its valid_until — the last day those credits can be spent — soonest
first, so an agent can tell you when to use what is left.
Arguments: none.