Drive your app store rank tracking from your own code: a REST API with scoped keys and per-key rate limits over the apps and search terms you track across the iOS App Store, Google Play and the Microsoft Store, plus signed webhooks when something changes.
API keys
The AppSkyline REST API lets your own backend work with what the dashboard shows: the apps your organization tracks, the search terms tracked for each of them across the iOS App Store, Google Play and the Microsoft Store, and the store engagement rows behind the stats pages.
Open the AppSkyline dashboard and create an API key under API keys. The secret is shown once, when the key is created, and never again — store it somewhere safe. A key belongs to a single organization, so the organization is implied by the key and never has to be sent.
Authenticate every request with HTTP Basic auth carrying only the key secret, base64-encoded, in the Authorization header.
# The Authorization header is HTTP Basic auth carrying only the key secret,
# with no username and no colon.
Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)Every endpoint lives under https://api.appskyline.com. Requests made with a key are rate limited per key; going over the limit returns 429.
Quick start
List your tracked apps, start tracking a new search term for one of them, then read the terms tracked for that app.
# List the apps your organization tracks
curl https://api.appskyline.com/api/apps \
-H "Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)"
# Track a new search term for one of them. country is a two-letter ISO code and
# language a two-letter ISO code; the pair is the storefront the term is
# ranked in.
curl -X POST https://api.appskyline.com/api/keywords \
-H "Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)" \
-H "Content-Type: application/json" \
-d '{
"appId": "APP_ID",
"searchTerms": "dental practice software",
"country": "us",
"language": "en"
}'
# Read back the terms tracked for that app
curl "https://api.appskyline.com/api/keywords?appId=APP_ID&limit=50" \
-H "Authorization: Basic $(printf %s YOUR_API_KEY_SECRET | base64)"Browse the full API reference — every endpoint with its parameters, request body, responses and required scope.
CLI
The same apps, keywords and rankings are available from your terminal through the appskyline CLI. Install it globally with npm, or run it ad hoc with npx.
Authentication is one command: appskyline login opens your browser to sign in to your AppSkyline account and stores a session for later commands — no API key to paste.
# Install once, globally
npm install -g appskyline
# or run it ad hoc without installing
npx appskyline --help
# Log in — opens your browser to sign in and stores a session
appskyline login
# List the apps your organization tracks
appskyline apps list
# Where does your app rank right now for a term?
appskyline rank APP_ID --store ios-app-store --term "dental practice software" --country US
# Live top-10 results for a term on a store
appskyline search ios-app-store --term "dental practice software" --country US
# Search volume, CPC and difficulty for keyword ideas
appskyline keywords overview --country US --terms "dental software,dentist app"The CLI is open source at github.com/appskyline/cli and published as appskyline on npm. Run any command with --help to see its options.
Claude connector
Connect AppSkyline to Claude to ask about the apps your organization tracks, the search terms you monitor and their current store rankings. The connector uses your AppSkyline account, so Claude can only access the organization you authorize.
In Claude, open Settings, choose Connectors, then add a custom connector with the URL below. Claude sends you to AppSkyline to sign in and approve access. After connecting, ask a natural-language question such as “What is our current rank for restaurant POS on the iOS App Store in the United States?”
# In Claude: Settings > Connectors > Add custom connector
# Connector URL
https://mcp.appskyline.com/mcp
# Then sign in to your AppSkyline account when Claude asks you to connect.
# Example prompt: "Show the current App Store rank for one of my apps."The connector has separate read and write tools. Claude identifies changes before performing them, while rank lookups can render a compact inline result with the app, store, country, keyword and current position.
You need an AppSkyline account with access to at least one tracked app. To remove access later, disconnect AppSkyline in Claude or revoke the connection from your AppSkyline account.
Other MCP clients
AppSkyline speaks the Model Context Protocol over streamable HTTP, so it works with any client that supports remote MCP servers — not only Claude. There is nothing to install and no API key to paste: point the client at the URL below and sign in to AppSkyline when it asks.
# Any MCP client that supports remote servers uses the same URL:
https://mcp.appskyline.com/mcp
# Codex CLI
codex mcp add appskyline --url https://mcp.appskyline.com/mcp
codex mcp login appskyline
# VS Code
code --add-mcp '{"name":"appskyline","type":"http","url":"https://mcp.appskyline.com/mcp"}'
# Cursor, Windsurf and other editors: add to their MCP config file
{
"mcpServers": {
"appskyline": {
"type": "http",
"url": "https://mcp.appskyline.com/mcp"
}
}
}
# Clients that only support local (stdio) servers can bridge:
npx mcp-remote https://mcp.appskyline.com/mcpThis is also an MCP App server implementing the standard io.modelcontextprotocol/ui extension. The show_app_overview tool renders ui://appskyline/app-overview-v13.html, and keyword-rank results render ui://appskyline/keyword-rank-v6.html. Both resources use text/html;profile=mcp-app, declare a restrictive inline Content Security Policy scoped to the MCP and host origins, and support light/dark color schemes in compatible hosts including Claude and ChatGPT.
Authentication uses OAuth 2.0 with dynamic client registration and PKCE, which means clients register themselves — you never copy a client id or secret. Clients that only support local servers can bridge to the remote endpoint with mcp-remote.
AppSkyline signs in through the same authorization server as our other products, so the approval screen may list scopes for products beyond AppSkyline. Access is pinned to the product you connected: a token issued for AppSkyline is only accepted by AppSkyline, and you can revoke it at any time from your account.
Documentation MCP
AppSkyline publishes a separate public, read-only MCP endpoint for documentation. It searches and reads the canonical product overview, developer guide, REST API, authentication, pricing, and privacy Markdown without accessing an organization or requiring an account.
# Public read-only documentation server
https://mcp.appskyline.com/docs-mcp
# No AppSkyline account or OAuth token is required.
# Available tools: search_appskyline_documentation and get_appskyline_documentationUse search_appskyline_documentation when you do not know which page answers the question, then use get_appskyline_documentation for the complete cited source. Product actions and private rank data remain on the OAuth-protected AppSkyline MCP server.
Agent Plugins
The open Agent Plugins standard packages the AppSkyline MCP server and its ASO research skill together. Install one repository and your agent learns the workflow, connects to the remote tools, and sends you through the same AppSkyline OAuth approval flow — no API key or client secret is bundled in the plugin.
# Portable Agent Plugins package (Kiro, Cursor, Copilot-compatible hosts)
https://github.com/appskyline/claude-plugin
# Gemini CLI
gemini extensions install https://github.com/appskyline/claude-plugin
# Google Antigravity uses its native adapter from the same repository
git clone https://github.com/appskyline/claude-plugin.git
agy plugin install ./claude-plugin/com.google.antigravityThe repository includes the portable plugin.json and mcp.json manifests, plus native adapters for Claude, Gemini CLI, and Google Antigravity. The portable package is also the submission artifact for Kiro Powers, the Cursor Marketplace, and Awesome Copilot.
Agents and registries can discover the same package from the well-known Agent Plugin manifest or from AppSkyline’s AI Catalog.
Agent Skills
AppSkyline ships Agent Skills — guides following the agentskills.io standard that teach coding agents how to run ASO research with the appskyline CLI and the MCP connector, instead of guessing at commands and tools.
# Install the AppSkyline skills into your coding agent
npx skills add appskyline/skillsOne command installs the skills into Claude Code, Cursor, Codex, Gemini CLI and any other agent that follows the Skills standard. The CLI also bundles the same guides, version-matched to the commands it ships: appskyline skills get <name> prints one on demand.
The skills are open source at github.com/appskyline/skills. Claude users can also install the AppSkyline Claude plugin, which bundles the connector together with the skills: github.com/appskyline/claude-plugin.
Scopes
Each key carries a list of scopes, so an integration that only needs to read your rankings never gets the ability to change what is tracked. New keys start read-only; widen them explicitly in the dashboard. A request whose key is missing the scope an endpoint requires is refused with 403.
Webhooks
Add a webhook subscription to your organization and AppSkyline POSTs the events you picked to your server as they happen.
POST https://your-server.com/appskyline-webhook
X-Appskyline-Event: keyword.created
X-Appskyline-Signature: t=1719000000,v1=<hmac-sha256 hex>
Content-Type: application/json
{
"event": "keyword.created",
"timestamp": 1719000000,
"data": { "...": "..." }
}Every delivery carries an X-Appskyline-Signature header of the form t=timestamp,v1=signature, where the signature is an HMAC-SHA256 of timestamp.body keyed by the subscription secret shown to you once when the subscription was created. Recompute it over the raw body and compare before trusting the payload.
import crypto from 'node:crypto'
// body must be the RAW request body, byte for byte
function verify(header, body, secret) {
const [t, v1] = (header || '').split(',').map(part => part.split('=')[1])
if (!t || !v1) return false
const expected = crypto
.createHmac('sha256', secret)
.update(`${t}.${body}`)
.digest('hex')
// timingSafeEqual throws on a length mismatch, so a malformed signature
// has to be rejected before the comparison rather than by it.
if (v1.length !== expected.length) return false
return crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(expected))
}Delivery is one best-effort attempt with a five second timeout and no retries, so respond 2xx quickly and do the work asynchronously. An endpoint that fails twenty times in a row is disabled automatically and has to be re-enabled in the dashboard.
Start building