{
  "openapi": "3.0.1",
  "info": {
    "title": "SEO: Ranking Keywords & Internal Links",
    "description": "Find keywords Google shows but nobody clicks: striking distance, low CTR, cannibalization and content gaps from Search Console data. Get an internal link plan, content briefs and a did-it-work tracker.",
    "version": "0.1",
    "x-build-id": "iOsmXAVQ8x8AjZueW"
  },
  "servers": [
    {
      "url": "https://api.apify.com/v2"
    }
  ],
  "paths": {
    "/acts/apizilla~seo-ranking/run-sync-get-dataset-items": {
      "post": {
        "operationId": "run-sync-get-dataset-items-apizilla-seo-ranking",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    },
    "/acts/apizilla~seo-ranking/runs": {
      "post": {
        "operationId": "runs-sync-apizilla-seo-ranking",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor and returns information about the initiated run in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/runsResponseSchema"
                }
              }
            }
          }
        }
      }
    },
    "/acts/apizilla~seo-ranking/run-sync": {
      "post": {
        "operationId": "run-sync-apizilla-seo-ranking",
        "x-openai-isConsequential": false,
        "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
        "tags": [
          "Run Actor"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/inputSchema"
              }
            }
          }
        },
        "parameters": [
          {
            "name": "token",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Enter your Apify token here"
          }
        ],
        "responses": {
          "200": {
            "description": "OK"
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "inputSchema": {
        "type": "object",
        "required": [
          "siteUrl"
        ],
        "properties": {
          "siteUrl": {
            "title": "Site URL",
            "type": "string",
            "description": "The site to analyse, for example https://example.com (a domain like example.com or sc-domain:example.com also works). The crawl stays on this host."
          },
          "gscCsvUrls": {
            "title": "Search Console CSV or ZIP files",
            "type": "array",
            "description": "Easy way: upload the Search Console export (Performance > Export > Download CSV or ZIP) or paste links to it. A ZIP with Queries.csv and Pages.csv works as it is. A table with Query + Page columns (from the API, Looker Studio or Sheets) gives the best results (exact pages and cannibalization). A Google Sheets link works when the sheet is public or published. The link must open without logging in."
          },
          "gscCsvText": {
            "title": "Or paste the CSV",
            "type": "string",
            "description": "Paste the CSV text here instead of a file (first line = header with Query, Clicks, Impressions, CTR, Position, and optionally Page). Useful for API calls and small tests."
          },
          "googleServiceAccountJson": {
            "title": "Google service account key (API)",
            "type": "string",
            "description": "Automatic way: paste the whole JSON key of a Google Cloud service account. In Search Console open Settings > Users and permissions and add the service account email as a user (Restricted is enough). Enable the 'Google Search Console API' in the Cloud project. Stored encrypted."
          },
          "gscProperty": {
            "title": "Search Console property",
            "type": "string",
            "description": "Only with the API. The property exactly as in Search Console: sc-domain:example.com for a domain property or https://example.com/ for a URL-prefix property. Leave empty to pick the property of the Site URL automatically."
          },
          "googleClientId": {
            "title": "OAuth client ID (API, alternative)",
            "type": "string",
            "description": "Alternative to the service account: OAuth client ID, client secret and refresh token of a Google account that can see the property (scope webmasters.readonly)."
          },
          "googleClientSecret": {
            "title": "OAuth client secret",
            "type": "string",
            "description": "OAuth client secret (stored encrypted)."
          },
          "googleRefreshToken": {
            "title": "OAuth refresh token",
            "type": "string",
            "description": "OAuth refresh token (stored encrypted)."
          },
          "days": {
            "title": "Days of data",
            "minimum": 7,
            "maximum": 480,
            "type": "integer",
            "description": "API: how many days to read (Search Console keeps 16 months). CSV: tell the Actor how many days your export covers (default 28), used to turn clicks into clicks per day for the progress report.",
            "default": 28
          },
          "endDateLagDays": {
            "title": "Skip the last days (API)",
            "minimum": 0,
            "maximum": 10,
            "type": "integer",
            "description": "Search Console data is final after about 2 to 3 days. The API window ends this many days before today.",
            "default": 3
          },
          "searchType": {
            "title": "Search type (API)",
            "enum": [
              "web",
              "image",
              "video",
              "news",
              "discover",
              "googleNews"
            ],
            "type": "string",
            "description": "Which Google search results to read.",
            "default": "web"
          },
          "country": {
            "title": "Country filter (API)",
            "type": "string",
            "description": "Optional 3-letter country code (for example USA, GBR, DEU, PRT) to read only one country."
          },
          "maxGscRows": {
            "title": "Max rows from the API",
            "minimum": 1000,
            "maximum": 250000,
            "type": "integer",
            "description": "Stops reading after this many query+page rows (25,000 per API call).",
            "default": 50000
          },
          "brandTerms": {
            "title": "Brand terms to ignore",
            "type": "array",
            "description": "Queries that contain one of these words are skipped (people who search your brand already know you, and their CTR is very different). Example: your company name.",
            "items": {
              "type": "string"
            }
          },
          "opportunityTypes": {
            "title": "Opportunity types",
            "type": "array",
            "description": "Striking distance: position 8 to 50 with many impressions (no-click keywords are flagged). Low CTR: page-1 keywords whose CTR is far below normal for the position (rewrite title/meta). Cannibalization: several of your pages compete for the same queries. Content gap: no page of yours fits the query (write a new guide).",
            "items": {
              "type": "string",
              "enum": [
                "striking_distance",
                "ctr_underperformer",
                "cannibalization",
                "content_gap"
              ],
              "enumTitles": [
                "Striking distance / no-click",
                "Low CTR (rewrite title and meta)",
                "Cannibalization",
                "Content gap (new guide)"
              ]
            },
            "default": [
              "striking_distance",
              "ctr_underperformer",
              "cannibalization",
              "content_gap"
            ]
          },
          "minImpressions": {
            "title": "Min impressions",
            "minimum": 5,
            "type": "integer",
            "description": "An opportunity needs at least this many impressions in the period (all related queries together).",
            "default": 100
          },
          "minPosition": {
            "title": "Closest position",
            "minimum": 2,
            "maximum": 50,
            "type": "number",
            "description": "Striking distance starts at this average position. Page-1 queries above it are checked for low CTR instead.",
            "default": 8
          },
          "maxPosition": {
            "title": "Furthest position",
            "minimum": 10,
            "maximum": 100,
            "type": "number",
            "description": "Striking distance ends at this average position. Queries ranking further away only count as content gaps.",
            "default": 50
          },
          "targetPosition": {
            "title": "Target position",
            "minimum": 1,
            "maximum": 10,
            "type": "number",
            "description": "Extra clicks are estimated if the query reached this position (default 3 = top 3).",
            "default": 3
          },
          "ctrUnderperformRatio": {
            "title": "Low CTR threshold",
            "minimum": 0.1,
            "maximum": 0.9,
            "type": "number",
            "description": "A page-1 query is a CTR problem when its CTR is below this share of the normal CTR for its position (0.5 = less than half).",
            "default": 0.5
          },
          "maxOpportunities": {
            "title": "Max opportunities",
            "minimum": 1,
            "maximum": 1000,
            "type": "integer",
            "description": "Only the best opportunities by priority score are saved (and charged).",
            "default": 100
          },
          "crawlSite": {
            "title": "Crawl the site",
            "type": "boolean",
            "description": "Read your pages (sitemap first) to match queries to pages, decide 'optimize' or 'create new guide', plan internal links and find orphan pages. Turn off to analyse the Search Console data only.",
            "default": true
          },
          "maxPages": {
            "title": "Max pages to crawl",
            "minimum": 1,
            "maximum": 2000,
            "type": "integer",
            "description": "Pages with Search Console impressions are crawled first, then the home page, then the sitemap. Never more than 40% of your maximum cost for the run is spent on the crawl.",
            "default": 200
          },
          "sitemapUrls": {
            "title": "Sitemap URLs",
            "type": "array",
            "description": "Optional. Leave empty to find the sitemap in robots.txt or at /sitemap.xml.",
            "items": {
              "type": "string"
            }
          },
          "excludeUrlPatterns": {
            "title": "Skip URLs matching",
            "type": "array",
            "description": "Regular expressions. A URL that matches one is not crawled. Example: /tag/ or \\?replytocom=",
            "items": {
              "type": "string"
            }
          },
          "respectRobotsTxt": {
            "title": "Respect robots.txt",
            "type": "boolean",
            "description": "Do not crawl URLs that robots.txt blocks for all crawlers.",
            "default": true
          },
          "crawlConcurrency": {
            "title": "Parallel requests",
            "minimum": 1,
            "maximum": 8,
            "type": "integer",
            "description": "Pages read at the same time (a short delay between requests to the same site is always kept).",
            "default": 3
          },
          "maxBriefs": {
            "title": "Max content briefs",
            "minimum": 0,
            "maximum": 100,
            "type": "integer",
            "description": "Content briefs (target keyword, secondary keywords, title and meta options, outline, questions, word count, links, schema) for the best opportunities. 0 = none. Each brief is one 'content brief' event.",
            "default": 10
          },
          "maxLinksPerTarget": {
            "title": "Internal links per target page",
            "minimum": 0,
            "maximum": 20,
            "type": "integer",
            "description": "For each page to improve (or new guide) suggest up to this many pages that should link to it, with anchor text and where to put the link. 0 = no link plan. Each suggestion is one 'internal link suggestion' event.",
            "default": 5
          },
          "maxLinkTargets": {
            "title": "Max target pages for the link plan",
            "minimum": 0,
            "maximum": 200,
            "type": "integer",
            "description": "The link plan covers the best opportunities up to this many different target pages.",
            "default": 25
          },
          "includeOrphanLinks": {
            "title": "Also fix orphan pages",
            "type": "boolean",
            "description": "Suggest 2 links for each of up to 10 orphan pages (pages with no internal links pointing to them).",
            "default": true
          },
          "newGuidePath": {
            "title": "Folder for new guides",
            "type": "string",
            "description": "Planned URLs of new guides look like https://yoursite.com/<folder>/<keyword-slug>.",
            "default": "/guides/"
          },
          "llmProvider": {
            "title": "Write guide drafts with your own AI key",
            "enum": [
              "none",
              "openai",
              "anthropic",
              "gemini"
            ],
            "type": "string",
            "description": "Optional. With your own API key the Actor also writes a full draft of each guide from its brief. Without a key you only get the brief. The Actor never uses a key of ours. The AI provider bills you directly for the tokens; the Actor only charges its 'guide draft' event.",
            "default": "none"
          },
          "llmApiKey": {
            "title": "Your AI API key",
            "type": "string",
            "description": "API key of the provider above. Stored encrypted, sent only to that provider, never saved in the results."
          },
          "llmModel": {
            "title": "AI model",
            "type": "string",
            "description": "Model ID of the provider. Leave empty for a small, cheap default (OpenAI gpt-6-luna, Claude claude-haiku-5-5, Gemini gemini-3.5-flash-lite). Model names change: set this if the default is retired."
          },
          "maxDrafts": {
            "title": "Max guide drafts",
            "minimum": 0,
            "maximum": 20,
            "type": "integer",
            "description": "How many drafts to write (best opportunities first). Each draft is one 'guide draft' event plus your own AI cost.",
            "default": 3
          },
          "trackChanges": {
            "title": "Track progress between runs",
            "type": "boolean",
            "description": "Save a baseline (in a named storage per tracker) and compare the next run with it: new, improved, regressed and fixed opportunities, pages you edited, links you added. Google needs about 3 to 4 days to register changes, so run every 4 to 7 days.",
            "default": true
          },
          "trackerName": {
            "title": "Tracker name",
            "type": "string",
            "description": "Runs with the same name share one baseline. Default: the site's domain."
          },
          "resetBaseline": {
            "title": "Start over",
            "type": "boolean",
            "description": "Ignore the saved baseline and save a new one in this run.",
            "default": false
          }
        }
      },
      "runsResponseSchema": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "actId": {
                "type": "string"
              },
              "userId": {
                "type": "string"
              },
              "startedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "finishedAt": {
                "type": "string",
                "format": "date-time",
                "example": "2025-01-08T00:00:00.000Z"
              },
              "status": {
                "type": "string",
                "example": "READY"
              },
              "meta": {
                "type": "object",
                "properties": {
                  "origin": {
                    "type": "string",
                    "example": "API"
                  },
                  "userAgent": {
                    "type": "string"
                  }
                }
              },
              "stats": {
                "type": "object",
                "properties": {
                  "inputBodyLen": {
                    "type": "integer",
                    "example": 2000
                  },
                  "rebootCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "restartCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "resurrectCount": {
                    "type": "integer",
                    "example": 0
                  },
                  "computeUnits": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "options": {
                "type": "object",
                "properties": {
                  "build": {
                    "type": "string",
                    "example": "latest"
                  },
                  "timeoutSecs": {
                    "type": "integer",
                    "example": 300
                  },
                  "memoryMbytes": {
                    "type": "integer",
                    "example": 1024
                  },
                  "diskMbytes": {
                    "type": "integer",
                    "example": 2048
                  }
                }
              },
              "buildId": {
                "type": "string"
              },
              "defaultKeyValueStoreId": {
                "type": "string"
              },
              "defaultDatasetId": {
                "type": "string"
              },
              "defaultRequestQueueId": {
                "type": "string"
              },
              "buildNumber": {
                "type": "string",
                "example": "1.0.0"
              },
              "containerUrl": {
                "type": "string"
              },
              "usage": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "integer",
                    "example": 1
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              },
              "usageTotalUsd": {
                "type": "number",
                "example": 0.00005
              },
              "usageUsd": {
                "type": "object",
                "properties": {
                  "ACTOR_COMPUTE_UNITS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATASET_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "KEY_VALUE_STORE_WRITES": {
                    "type": "number",
                    "example": 0.00005
                  },
                  "KEY_VALUE_STORE_LISTS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_READS": {
                    "type": "integer",
                    "example": 0
                  },
                  "REQUEST_QUEUE_WRITES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_INTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "DATA_TRANSFER_EXTERNAL_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_SERPS": {
                    "type": "integer",
                    "example": 0
                  },
                  "PROXY_UNBLOCKER_UNITS": {
                    "type": "integer",
                    "example": 0
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}