Changelog
Unreleased
ADDED
- ›Web: account dashboard at openaso.ai — sign in with email + password (Better Auth; sessions on the site, keys still header-auth on the API), see today's tool-call usage against the daily quota, and mint or revoke API keys self-serve (up to 5 active). Accounts link by email, so a key issued via the old
POST /signupand a dashboard login with the same address are one account; lost-key recovery is now self-serve instead of email-support. Newauth_*tables (migration20260728000000_web_auth.sql).
REMOVED
- ›Hosted: anonymous
POST /signup(email in, key out) is retired — API keys now require an account, created at openaso.ai/login and minted in the dashboard. The endpoint answers410 Gonewith that pointer (CORS kept for cached clients). Account-creation abuse caps (3/IP/day + a fleet-wide daily cap) move to the dashboard path unchanged;OPENASO_SIGNUP_DAILY_CAPis no longer read, and the newOPENASO_SITE_URL(defaulthttps://openaso.ai) feeds the landing page and the 410 pointer. - ›
revenuecommand + MCP tool: order-of-magnitude revenue estimates modeled from the app's public top-grossing chart rank — the one monetization signal Apple publishes for arbitrary apps. Daily/monthly gross-consumer-spend bands in USD (low/mid/high; developer proceeds ~70-85% of gross), from a power-law fit ($4.0M x rank^-0.95on the US overall chart, calibrated 2026-07 against published rank-revenue datapoints: ChatGPT/ TikTok/MONOPOLY GO! press figures, Cal AI founder-public numbers, Distimo 2013 thresholds, the DazeEnd/Overcast 2015 curve), scaled per storefront (iOS spend share vs US) and per genre chart (spend share through the power law). Falls back from the overall chart to the app's genre grossing chart; apps on no consulted top 100 getupperBoundDailyonly. Bands carry a 2.5x multiplier and a note stating the model's limits — estimates, never Apple data. - ›
chartsnow reportstopGrossingalongside top-free/top-paid, served by the legacyitunes.apple.comRSS feed (ITunesClient.topGrossing, per- genre capable) — the only public source of grossing ranks; the modern marketing-tools feed deliberately omits grossing. Additive JSON change: per-storefront results gain atopGrossingfield. - ›Hosted: the daily managed run now archives the overall top-grossing top-100 per storefront into the new
chart_snapshotstable (migration20260724000000_chart_snapshots.sql) for every tracked storefront plus US plusOPENASO_GROSSING_COUNTRIES— insurance against the legacy feed being retired, and the future calibration series for the revenue model. The run summary gains achartssection with its own failure list.
CHANGED
- ›**Real Apple Search Ads popularity for
volume(andaudit).** The headline demand number is nowpopularity(0-100): Apple's real Search Ads Search Popularity whensourceis"apple", served server-side by the hosted service through a single Apple Ads account (Apple exposes this only via the Apple Ads console's internal endpoint, not the official API). Apple floors low-demand keywords at 5 and returns nothing below its threshold or in storefronts outside Apple Ads coverage; there — and in local mode, which carries no credentials —sourceis"proxy"andpopularityfalls back to the independentestimate(the former blended score), withflooredandapplePopularityexposed for transparency. Breaking JSON contract: thevolumeper-storefrontvolumeScore/popularityScorefields are replaced bypopularity/source/applePopularity/floored/estimate;auditcandidates gainpopularity/popularitySource/applePopularity/floored/estimatein place ofvolumeScore. The popularity fetch never fails a tool call — an expired session or uncovered storefront simply degrades to the estimate. Configured viaOPENASO_APPLE_ADS_COOKIE+OPENASO_APPLE_ADS_ADAM_ID(see docs/HOSTED.md); cached per (storefront, keyword) for 24h in the shared L2 cache.
ADDED
- ›
auditcommand + MCP tool: one-call ASO research bundle per storefront — the app's current listing (title + web-scraped subtitle), its visible word pool, and scored keyword candidates (supplied phrases plus autocomplete discoveries seeded from the pool). Each candidate is scored from a single shared search: demand (popularity, the volume tool's model — real Apple Search Ads popularity where available, else the estimate), competition, incumbent strength (medianTopRatings) and the app's current rank — where separatevolume+rankcalls would search twice. Emits progress notifications; supplied phrases never compete with discoveries for thelimitslots. - ›
optimize_metadataMCP prompt (the server now declares thepromptscapability, served over stdio and hosted HTTP alike): a packaged metadata-optimization playbook the client's model executes with the tools — audit, deepen with reviews/competitors, choose targets, draft against coverage with{phrase, value: popularity}weights, regression-check that no currently-ranking phrase is silently dropped, then verify with rank and set up daily tracking. Prompt arguments:appId(required),countries,phrases(comma-separated). - ›
coverageword-value aggregation: target phrases accept{phrase, value}weights (CLI:"photo editor=87"), andwordValuessums each word's search value across every phrase it can combine into ("photo" serves "photo editor", "photo maker" and "take photo" at once). A phrase's value is credited to each of its words — totals are not additive across words — sounlockValue(absent words whose addition alone covers new phrases) andatRiskValue(a true drop-counterfactual: covered phrases that would actually break, respecting surviving plural variants) are the marginal numbers to budget the 30/30/100 characters by. - ›
coveragekeyword-field waste accounting (keywordFieldWaste): commas count toward the 100-character limit; spaces around commas, duplicates of title/subtitle words, in-field repeats, stopwords and the separators their removal frees are reported as reclaimable — never more than the field contains. The comma/space convention is now also taught in the server instructions and tool description. - ›
coveragecommand + MCP tool: metadata keyword coverage, pure local computation. Apple indexes the title, subtitle and hidden keyword field per locale as one combined word pool, so an app can rank for phrases assembled from words across fields — a model agents consuming the server did not reliably know.coverageoperationalizes it: combined pool with strongest-field attribution, cross-field duplicates (reclaimable characters), per-field character budgets (30/30/100), and per-phrase coverage (exact-in-field / cross-field / missing words, with plural and stopword handling). The serverinstructions, therank/apptool descriptions and anotein every coverage result now teach the combination model explicitly, so it survives hosts that drop server-level instructions.
0.3.0 (2026-07-22)
BREAKING
- ›CLI
--jsonoutput now always uses the canonical multi-storefront shape — the same shape the MCP tools return. Previously each command emitted a different, flatter JSON shape when a single--countrywas given, so adding a second country silently changed the schema. Single-storefront *text* output is unchanged. - ›
competitors --jsonrenamescounttoreturnedand addstotal(the API's result count, capped at 200), matching the MCP tool. The search always requests the full 200 results and slices tolimit, sototalis meaningful regardless of the limit. - ›
rank --jsonwith--saveemits flathistoryFile/prev/changefields (matching the MCP tool) instead of a nestedhistoryobject. - ›Exit codes are now meaningful: 0 success, 1 usage/validation error, 2 iTunes API/network failure, 3 app not found in any requested storefront (previously not-found exited 1, indistinguishable from usage errors).
- ›Relative
--history-file/--configpaths resolve against$OPENASO_HOMEwhen set (else the current directory, as before) and results echo resolved absolute paths. - ›The default politeness throttle between API requests is now 1000ms (was 250ms) to match the iTunes API's real rate limits.
ADDED
- ›
suggestcommand + MCP tool: App Store search-autocomplete suggestions (keyword discovery) via the public MZSearchHints endpoint. - ›
reviewscommand + MCP tool: recent customer reviews per storefront from the public RSS feed — rating distribution plus review texts. - ›
chartscommand + MCP tool: top-free / top-paid chart positions (top 100) from the public marketing-tools feed. - ›
historycommand + MCP tool: read the JSONL history back — per (keyword, app, storefront) series with current/previous/best/worst rank, filterable by keyword/app/country/date. No network. - ›
app --full(CLI) /full: true(MCP): return the complete iTunes lookup record, including the description — previously unreachable over MCP. - ›App summaries include
languages(localization coverage signal). - ›
--version; per-command--help; with--json, errors are emitted as JSON on stdout ({"error": {"message": ...}}). - ›MCP: tool annotations (
readOnlyHintetc.) and titles, serverinstructions, progress notifications fortrackwhen the client sends aprogressToken, cancellation support, full output schemas for competitors rows and app summaries, JSON-Schema constraints (min/max/default/pattern), unknown argument keys rejected, unknown tools rejected as protocol errors. - ›HTTP client: per-attempt timeout (10s default), authoritative
Retry-Aftersupport (capped at 60s, shorter or longer than the backoff), retry on malformed 200 bodies, junk chart/review feed bodies rejected instead of read as empty, response-body snippets andcausechaining in errors, race-free shared throttle, andAbortSignalsupport end to end — cancellation reaches every MCP tool's outbound requests and interrupts retry backoff and throttle waits promptly. - ›
trackfetches each keyword x storefront search once for all configured apps (was once per app) and indexes history in one read per run. - ›History appends recover from partial trailing lines (crash/disk-full) instead of corrupting the next record.
- ›Packaging:
filesallowlist,prepare/prepublishOnlybuild hooks, keywords/author/repository metadata, LICENSE file, CI workflow (Node 18/20/22),.openaso.example.json, type-checked tests (tsc -p tsconfig.test.json).
0.2.0
- ›Initial public shape:
rank,competitors,volume,app,trackcommands; MCP server over stdio; JSONL rank history with per-storefront change tracking; hermetic test suite.