Frase Analytics API

Google Search Console and performance data

GitHub OpenAPI

Operations 6

GET /analytics/gsc/overview Get GSC overview #
GET /analytics/gsc/queries Get top queries #
GET /analytics/gsc/pages Get top pages #
GET /analytics/gaps Get content gaps #
GET /analytics/alerts Get performance alerts #
POST /analytics/alerts/{id}/resolve Resolve alert #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/frase-io:frase-io-analytics-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Calls without X-API-Key need no key. Calls with it need a paid plan — get a key.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

frase-io-analytics-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: Frase Analytics API
  version: 1.0.0
  description: 'The Frase API provides programmatic access to your SEO content platform. Use it to manage content, research, audits, AI visibility tracking, and more. ## Authentication


    All API requests require authentication using an API key. Include your key in the `X-API-KEY` header:


    ```

    X-API-KEY: sk_live_your_api_key_here

    ```


    For legacy compatibility, the `token` header is also supported. ## Rate Limits


    Three independent limits apply, each with its own headers and error code. Headers are returned on `429` responses, not on successful ones. **Per-minute burst** - 60/min on trial and Starter, 120 Professional, 300 Scale, 1,000 Enterprise. Error code `rate_limit_exceeded`. - `X-RateLimit-Limit`, `X-RateLimit-Remaining`, `X-RateLimit-Reset` (epoch seconds)


    **Sustained hourly ceiling** - 2,000/hour trial, 3,000 Starter, 5,000 Professional, 15,000 Scale, 50,000 Enterprise. Error code `hourly_limit_exceeded`. - `X-RateLimit-Hourly-Limit`, `X-RateLimit-Hourly-Remaining`, `X-RateLimit-Hourly-Reset` (epoch seconds)


    **Monthly request budget** - error code `monthly_budget_exceeded`, headers `X-Monthly-Limit`, `X-Monthly-Used`, `X-Monthly-Remaining`. Every `429` carries `Retry-After` in seconds. On the hourly ceiling this can be up to 3,600, so clients should honour it rather than retrying on a short fixed backoff - a retry sooner than `Retry-After` cannot succeed. ## Errors


    The API uses standard HTTP status codes and returns errors in a consistent format:


    ```json

    {

    "error": {

    "type": "authentication_error",

    "code": "invalid_api_key",

    "message": "Invalid API key provided.",

    "doc_url": "https://docs.frase.io/api/errors#invalid_api_key"

    }

    }

    ```


    ## Changelog


    Breaking changes are listed here, newest first. "Breaking" means a field that was always present with a value can now be `null`, or an existing value now means something different — not that a field was removed or renamed. Additive fields are not listed. ### 2026-08-31 — Fact `sources[]` may omit `url`, and minted facts default to `approved`


    - `GET /briefs/{id}/facts`, `PATCH /briefs/{id}/facts/{factId}` → a `sources[]` entry may now carry only `title`, with no `url` or `domain`. Research names a publisher far more often than it captures a link (793 of 801 plan-evidence items in production), and those names were previously discarded rather than returned. Read `url` defensively. - `GET /briefs/{id}/facts` → `approval` on a newly minted fact is now `approved` rather than `pending`. A client polling for `pending` facts to review will see far fewer; rejection is unchanged and remains permanent. Facts the writer asserted in its own output (`provenance: generated`) are still minted `pending`. ### 2026-08-24 — Content Guard''s hasPublishedUrl is now recoverability, not the stored URL


    - `GET /content/{id}/monitoring` → `hasPublishedUrl`: was a judgment on the STORED URL (false for a relative path even when the page was live). It now answers "could Guard watch this article right now" — the stored URL when absolute, or an address the server recovers (CMS inventory; FraseCMS re-derivation from current settings when a live published post exists). `true` no longer implies the stored URL itself is absolute, and a FraseCMS article published before domain setup flips to `true` when setup finishes, with no re-publish. It remains exactly the condition enabling enforces. - `publishedUrlIssue` is now the RESIDUAL after recovery failed, not a raw-column classification — "not_absolute" can also mean the FraseCMS post is not live or FraseCMS is disabled for the site. - `POST /content/{id}/publish` → `url` (frase_cms): now derived from the site''s current CMS settings rather than the adapter''s host-of-the-moment value; the same URL is stored on the content row and sent in the content.published webhook.'
  contact:
    name: Frase Support
    url: https://frase.io
    email: support@frase.io
  license:
    name: Proprietary
    url: https://www.frase.io/company/terms
servers:
- url: https://next.frase.io/api/v1
  description: Production
- url: /api/v1
  description: This host
security:
- ApiKeyAuth: []
- BearerAuth: []
tags:
- name: Analytics
  description: Google Search Console and performance data
paths:
  /analytics/gsc/overview:
    get:
      operationId: getGSCOverview
      summary: Get GSC overview
      description: Get Google Search Console overview with 28-day comparison.
      tags:
      - Analytics
      parameters:
      - name: site_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: GSC overview data
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      site_id:
                        type: string
                      site_domain:
                        type: string
                      period:
                        type: object
                        properties:
                          current:
                            type: object
                            properties:
                              start:
                                type: string
                              end:
                                type: string
                          previous:
                            type: object
                            properties:
                              start:
                                type: string
                              end:
                                type: string
                      metrics:
                        type: object
                        properties:
                          clicks:
                            type: object
                            properties:
                              current:
                                type: integer
                              previous:
                                type: integer
                              change_percent:
                                type: number
                          impressions:
                            type: object
                            properties:
                              current:
                                type: integer
                              previous:
                                type: integer
                              change_percent:
                                type: number
                          ctr:
                            type: object
                            properties:
                              current:
                                type: number
                              previous:
                                type: number
                              change_percent:
                                type: number
                          position:
                            type: object
                            properties:
                              current:
                                type: number
                              previous:
                                type: number
                              change_percent:
                                type: number
                      summary:
                        type: object
                        properties:
                          unique_queries:
                            type: integer
                          unique_pages:
                            type: integer
                  request_id:
                    type: string
  /analytics/gsc/queries:
    get:
      operationId: getGSCQueries
      summary: Get top queries
      description: Get top search queries from GSC.
      tags:
      - Analytics
      parameters:
      - name: site_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: page_size
        in: query
        schema:
          type: integer
          default: 50
          maximum: 500
      - name: days
        in: query
        schema:
          type: integer
          default: 28
      - name: sort_by
        in: query
        schema:
          type: string
          enum:
          - clicks
          - impressions
          - ctr
          - position
          default: clicks
      responses:
        '200':
          description: Top queries
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        query:
                          type: string
                        clicks:
                          type: integer
                        impressions:
                          type: integer
                        ctr:
                          type: number
                        position:
                          type: number
                        pages_count:
                          type: integer
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  request_id:
                    type: string
  /analytics/gsc/pages:
    get:
      operationId: getGSCPages
      summary: Get top pages
      description: Get top pages by performance from GSC.
      tags:
      - Analytics
      parameters:
      - name: site_id
        in: query
        required: true
        schema:
          type: string
          format: uuid
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: page_size
        in: query
        schema:
          type: integer
          default: 50
      - name: days
        in: query
        schema:
          type: integer
          default: 28
      - name: sort_by
        in: query
        schema:
          type: string
          enum:
          - clicks
          - impressions
          - ctr
          - position
          default: clicks
      responses:
        '200':
          description: Top pages
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        page_url:
                          type: string
                        content_id:
                          type: string
                          nullable: true
                        content_title:
                          type: string
                          nullable: true
                        clicks:
                          type: integer
                        impressions:
                          type: integer
                        ctr:
                          type: number
                        position:
                          type: number
                        queries_count:
                          type: integer
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  request_id:
                    type: string
  /analytics/gaps:
    get:
      operationId: getContentGaps
      summary: Get content gaps
      description: 'Get content gap opportunities. By default the response EXCLUDES dismissed, completed and auto_resolved opportunities; pass ?status= to request them explicitly. The default response also EXCLUDES rows judged off-strategy - no cluster fit and no evidence from a CONFIRMED competitor (competitor URLs belonging to competitors still awaiting your review do not count, and relevance.reason then reads ''a competitor ranks for it, but that competitor is awaiting your review''); pass ?include_off_strategy=true to include them. `competitor_urls` is filtered to confirmed competitors'' hosts. Requesting a terminal status (completed, dismissed, auto_resolved) always returns the full set for that status - a strategy filter never hides history. An unrecognized status or type value returns 400 rather than being ignored.


        ### 2026-08-17 - Competitors are confirmed, not assumed


        BREAKING for default result sets: rows whose only competitor evidence belongs to unconfirmed competitors now default-exclude as off-strategy, and `competitor_urls` no longer includes unconfirmed competitors'' hosts. Confirm competitors in Brand Hub to restore their evidence.'
      tags:
      - Analytics
      parameters:
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: page_size
        in: query
        schema:
          type: integer
          default: 20
      - name: site_id
        in: query
        schema:
          type: string
          format: uuid
      - name: status
        in: query
        schema:
          type: string
          enum:
          - new
          - reviewed
          - in_progress
          - dismissed
          - completed
          - auto_resolved
        description: Filter by a single status. Omit for the default view, which excludes dismissed, completed and auto_resolved.
      - name: type
        in: query
        schema:
          type: string
          enum:
          - missing_content
          - thin_content
          - outdated_content
          - competitor_gap
      - name: include_off_strategy
        in: query
        required: false
        schema:
          type: boolean
        description: Include rows the default response filters out as off-strategy. Empty means not supplied; any other non-boolean value returns 400.
      responses:
        '200':
          description: Content gaps
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        site_id:
                          type: string
                          nullable: true
                        site_domain:
                          type: string
                          nullable: true
                        keyword:
                          type: string
                        search_volume:
                          type: integer
                          nullable: true
                        difficulty:
                          type: number
                          nullable: true
                        opportunity_type:
                          type: string
                        impressions:
                          type: integer
                          nullable: true
                        clicks:
                          type: integer
                          nullable: true
                        avg_position:
                          type: number
                          nullable: true
                        page_url:
                          type: string
                          nullable: true
                        existing_content_id:
                          type: string
                          nullable: true
                        suggested_brief_id:
                          type: string
                          nullable: true
                        competitor_urls:
                          type: array
                          items:
                            type: string
                          nullable: true
                        competitor_analysis:
                          type: object
                          nullable: true
                        status:
                          type: string
                        relevance:
                          type: object
                          nullable: true
                          description: How far this topic travels. Suggestion rows carry the derived bucket and reason; update rows about your OWN pages are always confident. Makes include_off_strategy and the terminal-status exemption actionable.
                          properties:
                            bucket:
                              type: string
                              enum:
                              - confident
                              - uncertain
                              - off_strategy
                            reason:
                              type: string
                        created_at:
                          type: string
                          format: date-time
                        updated_at:
                          type: string
                          format: date-time
                          nullable: true
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  request_id:
                    type: string
        '400':
          description: Invalid status, type or site_id value
  /analytics/alerts:
    get:
      operationId: getPerformanceAlerts
      summary: Get performance alerts
      description: Get performance alerts (traffic drops, etc.).
      tags:
      - Analytics
      parameters:
      - name: page
        in: query
        schema:
          type: integer
          default: 1
      - name: page_size
        in: query
        schema:
          type: integer
          default: 20
      - name: status
        in: query
        schema:
          type: string
          enum:
          - unresolved
          - resolved
          - all
        description: Filter by resolution status
      - name: severity
        in: query
        schema:
          type: string
          enum:
          - low
          - medium
          - high
          - critical
      - name: type
        in: query
        schema:
          type: string
          enum:
          - ranking_drop
          - traffic_drop
          - decay_detected
      responses:
        '200':
          description: Performance alerts
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                          format: uuid
                        content_id:
                          type: string
                          nullable: true
                        content_title:
                          type: string
                          nullable: true
                        content_status:
                          type: string
                          nullable: true
                        type:
                          type: string
                        severity:
                          type: string
                        title:
                          type: string
                        description:
                          type: string
                        data:
                          type: object
                        has_optimization:
                          type: boolean
                        resolved_at:
                          type: string
                          format: date-time
                          nullable: true
                        resolution:
                          type: string
                          nullable: true
                        created_at:
                          type: string
                          format: date-time
                  pagination:
                    $ref: '#/components/schemas/Pagination'
                  request_id:
                    type: string
  /analytics/alerts/{id}/resolve:
    post:
      operationId: resolveAlert
      summary: Resolve alert
      description: Mark an alert as resolved.
      tags:
      - Analytics
      parameters:
      - name: id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                resolution:
                  type: string
                  maxLength: 1000
      responses:
        '200':
          description: Alert resolved
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: object
                    properties:
                      id:
                        type: string
                        format: uuid
                      resolved_at:
                        type: string
                        format: date-time
                      resolution:
                        type: string
                        nullable: true
                      message:
                        type: string
                  request_id:
                    type: string
components:
  schemas:
    Pagination:
      type: object
      properties:
        page:
          type: integer
        page_size:
          type: integer
        total:
          type: integer
        has_more:
          type: boolean
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-KEY
      description: 'API key for authentication. Get your key from Settings > API Keys. You may also send the same key as `Authorization: Bearer <key>` — see BearerAuth.'
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Frase API key (sk_live_* / sk_test_*) or MCP access token (mcp_at_*)
      description: 'Send either your API key or an MCP access token as `Authorization: Bearer <token>`. An API key sent this way is exactly equivalent to sending it in X-API-KEY — same identity, same scopes, same rate limits — so use whichever your HTTP client makes natural. X-API-KEY takes precedence if you somehow send both. Cookie/session auth is intentionally NOT supported on /api/v1/* endpoints.'