Composway Docs
Cookbook

Turn findings into one work queue

Answer "what should I work on" with four kinds of finding priced in a single unit, then drill into the ones you pick.

Use this when nothing is obviously broken and you want a ranked list rather than an investigation. One tool does the ranking; the value of the recipe is in what you do with a row after you pick it.

list_sites - resolve the exact domain, and check which engines the site has.

score_seo_opportunities

Read estimatedClicks with its basis - every row is priced in clicks per windowDays at stake if the finding were fixed. A decay row is clicks that were measurably earned and lost; the other three are projections onto the site's own CTR curve. estimateBases in the response spells each one out.

Drill into the rows you actually chose - the queue fixes each source's thresholds at its defaults, so once a row is picked, its own tool is the better read: find_content_decay for the changepoint behind a decay row, get_query_pages for which page a low-hanging query is already ranking with, get_page_queries for what a page is carrying before you rewrite its title.

Check cannibalization before optimizing a page - detect_keyword_cannibalization with the query. "No page ranks well for this" and "several of our pages are splitting it" look identical in a queue and want opposite work: strengthening one of two competing pages makes the split worse.

Reading the queue honestly

Do not add the signals up

estimatedClicks takes the maximum of overlapping signals on one entity, never the sum - a query that is both low-hanging and under-clicking is one recovery, not two. A null value means the site's data could not price that row, not that it is worth zero; those rows sort last.

  • The queue mixes queries and pages (entityType), because the four sources work on different objects. The same string as a query and as a page is two rows.
  • Say what was evaluated. sources reports which types ran, which you excluded, and how many candidates each produced. A ranked queue reads as "these are the best available actions" in a way a filtered list does not - so when the response declares a truncated window, it is a top-N of what was visible, not of the site.