> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aitasker.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Get Brand Intelligence Seo Group Insights Route

> Cohort SEO analysis for one competitor Brand Group (INSIGHTS tab).

POST because the cohort is a client-curated domain set, mirroring the Paid
Media group route. An empty ``domains`` list means "the whole tracked set".
Reads only already-persisted DataForSEO data — no new provider spend.



## OpenAPI

````yaml /openapi.json post /api/v1/brands/{brand_id}/brand-intelligence/seo-group-insights
openapi: 3.1.0
info:
  title: AITasker
  version: 0.1.0
servers: []
security: []
paths:
  /api/v1/brands/{brand_id}/brand-intelligence/seo-group-insights:
    post:
      tags:
        - Brand Intelligence
        - Brand Intelligence
      summary: Get Brand Intelligence Seo Group Insights Route
      description: >-
        Cohort SEO analysis for one competitor Brand Group (INSIGHTS tab).


        POST because the cohort is a client-curated domain set, mirroring the
        Paid

        Media group route. An empty ``domains`` list means "the whole tracked
        set".

        Reads only already-persisted DataForSEO data — no new provider spend.
      operationId: >-
        get_brand_intelligence_seo_group_insights_route_api_v1_brands__brand_id__brand_intelligence_seo_group_insights_post
      parameters:
        - name: brand_id
          in: path
          required: true
          schema:
            type: string
            format: uuid
            title: Brand Id
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SeoGroupInsightsRequest'
      responses:
        '200':
          description: Successful Response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SeoGroupInsightsResponse'
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
      security:
        - HTTPBearer: []
components:
  schemas:
    SeoGroupInsightsRequest:
      properties:
        domains:
          items:
            type: string
          type: array
          maxItems: 60
          title: Domains
        group_label:
          anyOf:
            - type: string
              maxLength: 120
            - type: 'null'
          title: Group Label
      type: object
      title: SeoGroupInsightsRequest
    SeoGroupInsightsResponse:
      properties:
        module:
          type: string
          const: seo
          title: Module
          default: seo
        brand_id:
          type: string
          format: uuid
          title: Brand Id
        generated_at:
          type: string
          format: date-time
          title: Generated At
        group_key:
          type: string
          title: Group Key
        group_label:
          anyOf:
            - type: string
            - type: 'null'
          title: Group Label
        brand_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Brand Domain
        domains:
          items:
            type: string
          type: array
          title: Domains
        cohort_domains:
          items:
            type: string
          type: array
          title: Cohort Domains
        coverage:
          $ref: '#/components/schemas/ModuleCoverageStrip'
        position:
          items:
            $ref: '#/components/schemas/ModuleDimensionRank'
          type: array
          title: Position
        concentration:
          $ref: '#/components/schemas/SeoVisibilityConcentration'
        table_stakes:
          $ref: '#/components/schemas/SeoTableStakesPanel'
        content_type_mix:
          $ref: '#/components/schemas/SeoContentTypeMixPanel'
        keyword_intent_mix:
          $ref: '#/components/schemas/SeoKeywordIntentMixPanel'
        authority:
          $ref: '#/components/schemas/SeoAuthoritySpreadPanel'
        gaps:
          $ref: '#/components/schemas/SeoGapsPanel'
        weaknesses:
          $ref: '#/components/schemas/SeoWeaknessesPanel'
        findings:
          items:
            $ref: '#/components/schemas/ModuleRuleFinding'
          type: array
          title: Findings
        estimate_notice:
          type: string
          title: Estimate Notice
          default: ''
      type: object
      required:
        - brand_id
        - generated_at
        - group_key
      title: SeoGroupInsightsResponse
    HTTPValidationError:
      properties:
        detail:
          items:
            $ref: '#/components/schemas/ValidationError'
          type: array
          title: Detail
      type: object
      title: HTTPValidationError
    ModuleCoverageStrip:
      properties:
        targets_total:
          type: integer
          title: Targets Total
          default: 0
        measured:
          type: integer
          title: Measured
          default: 0
        missing:
          items:
            type: string
          type: array
          title: Missing
        fetch_failed:
          items:
            type: string
          type: array
          title: Fetch Failed
        persist_failed:
          items:
            type: string
          type: array
          title: Persist Failed
        skipped_cost:
          items:
            type: string
          type: array
          title: Skipped Cost
        last_run_at:
          anyOf:
            - type: string
              format: date-time
            - type: 'null'
          title: Last Run At
        brand_measured:
          type: boolean
          title: Brand Measured
          default: false
        brand_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Brand Domain
        brand_not_measured_reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Brand Not Measured Reason
        near_duplicate_pairs:
          items:
            $ref: '#/components/schemas/ModuleCoverageNearDuplicatePair'
          type: array
          title: Near Duplicate Pairs
        near_duplicate_scan_truncated:
          type: boolean
          title: Near Duplicate Scan Truncated
          default: false
        near_duplicate_scanned_count:
          type: integer
          title: Near Duplicate Scanned Count
          default: 0
      type: object
      title: ModuleCoverageStrip
      description: >-
        N-of-M acquisition coverage for one module's cohort (the ★S0/★C0 strip).


        ``measured`` counts cohort domains that produced a stored metric row.

        ``missing`` are targets that never did — their fetch or persist failed,
        or

        they have not been acquired yet. For Content, ``fetch_failed`` is a
        typed

        subset of ``missing``, not an additional shortfall, so clients must

        de-duplicate rather than sum those lengths. A competitor with a failed

        acquisition must render as a failure chip, never as a measured zero.
    ModuleDimensionRank:
      properties:
        dimension:
          type: string
          title: Dimension
        label:
          type: string
          title: Label
        higher_is_better:
          type: boolean
          title: Higher Is Better
          default: true
        brand_value:
          anyOf:
            - type: number
            - type: 'null'
          title: Brand Value
        brand_rank:
          anyOf:
            - type: integer
            - type: 'null'
          title: Brand Rank
        tied_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Tied Count
        measured_count:
          type: integer
          title: Measured Count
          default: 0
        cohort_total:
          type: integer
          title: Cohort Total
          default: 0
        best_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Best Domain
        best_tied_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Best Tied Count
        best_value:
          anyOf:
            - type: number
            - type: 'null'
          title: Best Value
        median_value:
          anyOf:
            - type: number
            - type: 'null'
          title: Median Value
        not_measured_reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Not Measured Reason
      type: object
      required:
        - dimension
        - label
      title: ModuleDimensionRank
      description: >-
        The user brand's standing on ONE measured dimension (★S1 / ★C1).


        ``brand_rank`` is 1-based over the domains that carry a value on this

        dimension — ``measured_count``. It is ``None`` when the brand itself is
        not

        measured on it, which is different from ranking last.


        It is a COMPETITION rank ("1224"): only strictly-better domains push the

        brand down, so tied domains share a place. ``tied_count`` is how many

        measured domains hold the brand's exact value, INCLUDING the brand — so
        it

        is 1 when the brand stands alone. Rank alone cannot carry a "you lead"

        claim (a brand tied at the top ranks 1, and so does a brand tied at zero

        with a cohort that measured zero); check ``tied_count == 1`` for that.


        ``best_tied_count`` is the same disclosure for ``best_domain``, which is

        ONE name chosen alphabetically out of the leaders. It counts inclusively

        too, so 1 means the named leader stands alone and a UI may safely name
        it.

        Both are ``None`` — never 0 — when there is nothing measured to count.
    SeoVisibilityConcentration:
      properties:
        measured_count:
          type: integer
          title: Measured Count
          default: 0
        total_est_traffic:
          anyOf:
            - type: number
            - type: 'null'
          title: Total Est Traffic
        top_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Top Domain
        top_tied_count:
          anyOf:
            - type: integer
            - type: 'null'
          title: Top Tied Count
        top_share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Top Share Pct
        top3_share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Top3 Share Pct
        brand_share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Brand Share Pct
        verdict:
          type: string
          enum:
            - concentrated
            - balanced
            - fragmented
            - not_measured
          title: Verdict
          default: not_measured
      type: object
      title: SeoVisibilityConcentration
      description: >-
        ★S2 — is the cohort's modelled organic traffic concentrated or spread.


        ``top_domain`` is ONE name out of the domains holding the highest
        measured

        traffic; ``top_tied_count`` counts them inclusively (1 = it really is
        one

        domain). Without it, two domains at 50%/50% render as one dominating the

        cohort — the ★S2 twin of the ``tied_count`` disclosure on

        ``ModuleDimensionRank``. ``None`` when nothing was measured, never 0.
    SeoTableStakesPanel:
      properties:
        cohort_domains_measured:
          type: integer
          title: Cohort Domains Measured
          default: 0
        threshold_domains:
          type: integer
          title: Threshold Domains
          default: 0
        keywords:
          items:
            $ref: '#/components/schemas/SeoTableStakesKeyword'
          type: array
          title: Keywords
        brand_missing_count:
          type: integer
          title: Brand Missing Count
          default: 0
        measured:
          type: boolean
          title: Measured
          default: false
        basis_notice:
          type: string
          title: Basis Notice
          default: >-
            Computed over the stored keyword samples for each competitor, not
            the full domain-wide keyword population.
      type: object
      title: SeoTableStakesPanel
      description: '★S3 — keywords the WHOLE measured cohort ranks for: the must-haves.'
    SeoContentTypeMixPanel:
      properties:
        rows:
          items:
            $ref: '#/components/schemas/SeoContentTypeMixRow'
          type: array
          title: Rows
        cohort_urls_classified:
          type: integer
          title: Cohort Urls Classified
          default: 0
        brand_urls_classified:
          type: integer
          title: Brand Urls Classified
          default: 0
        measured:
          type: boolean
          title: Measured
          default: false
        basis_notice:
          type: string
          title: Basis Notice
          default: >-
            Computed over the stored keyword samples for each competitor, not
            the full domain-wide keyword population.
      type: object
      title: SeoContentTypeMixPanel
      description: ★S6 — what KIND of page wins in this niche (classified ranking URLs).
    SeoKeywordIntentMixPanel:
      properties:
        rows:
          items:
            $ref: '#/components/schemas/SeoKeywordIntentMixRow'
          type: array
          title: Rows
        keywords_sampled:
          type: integer
          title: Keywords Sampled
          default: 0
        keywords_classified:
          type: integer
          title: Keywords Classified
          default: 0
        keywords_unclassified:
          type: integer
          title: Keywords Unclassified
          default: 0
        domains_measured:
          type: integer
          title: Domains Measured
          default: 0
        domains_not_measured:
          items:
            type: string
          type: array
          title: Domains Not Measured
        measured:
          type: boolean
          title: Measured
          default: false
        basis_notice:
          type: string
          title: Basis Notice
          default: >-
            Computed over the stored keyword samples for each competitor, not
            the full domain-wide keyword population.
      type: object
      title: SeoKeywordIntentMixPanel
      description: >-
        ★S5 — classified intent mix over the stored cohort keyword samples.


        ``keywords_unclassified`` is a separate denominator: missing labels are

        not folded into a bucket and domains whose classification call failed
        are

        named under ``domains_not_measured`` rather than represented as zeros.
    SeoAuthoritySpreadPanel:
      properties:
        enabled:
          type: boolean
          title: Enabled
          default: false
        measured_count:
          type: integer
          title: Measured Count
          default: 0
        dimensions:
          items:
            $ref: '#/components/schemas/ModuleDimensionRank'
          type: array
          title: Dimensions
        not_measured_reason:
          anyOf:
            - type: string
            - type: 'null'
          title: Not Measured Reason
      type: object
      title: SeoAuthoritySpreadPanel
      description: >-
        ★S8 — backlink/DR distribution and where the brand sits.


        ``enabled`` mirrors ``DATAFORSEO_BACKLINKS_ENABLED``; when it is off the

        authority metrics were never bought, so the panel is *not measured*
        rather

        than a cohort of zeros.
    SeoGapsPanel:
      properties:
        keywords:
          items:
            $ref: '#/components/schemas/SeoGapKeyword'
          type: array
          title: Keywords
        measured_domains:
          type: integer
          title: Measured Domains
          default: 0
        max_gap_population:
          anyOf:
            - type: integer
            - type: 'null'
          title: Max Gap Population
        semantics:
          type: string
          title: Semantics
          default: ''
        measured:
          type: boolean
          title: Measured
          default: false
      type: object
      title: SeoGapsPanel
      description: >-
        ★S9 — the cohort ranks, you don't.


        Rows come from DataForSEO's own server-side exclusion query

        (``domain_intersection`` with ``intersections: false``), so a keyword
        the

        brand ranks for at position 240 is not reported as a gap. ``semantics``

        names that contract; an empty string means the stored snapshot predates
        it.
    SeoWeaknessesPanel:
      properties:
        keywords:
          items:
            $ref: '#/components/schemas/SeoWeaknessKeyword'
          type: array
          title: Keywords
        competitors_measured:
          type: integer
          title: Competitors Measured
          default: 0
        shared_keywords_evaluated:
          type: integer
          title: Shared Keywords Evaluated
          default: 0
        max_competitor_position:
          type: integer
          title: Max Competitor Position
          default: 0
        min_position_delta:
          type: integer
          title: Min Position Delta
          default: 0
        measured:
          type: boolean
          title: Measured
          default: false
      type: object
      title: SeoWeaknessesPanel
      description: |-
        ★S10 — shared keywords where a competitor MATERIALLY outranks the brand.

        The thresholds are the free SEO audit's, imported rather than copied, so
        BI and the audit can never disagree on what "materially outranks" means.
    ModuleRuleFinding:
      properties:
        rule_id:
          type: string
          title: Rule Id
        module:
          type: string
          enum:
            - seo
            - content
            - reviews
            - social
            - google-ads
            - audits
          title: Module
        panel:
          type: string
          title: Panel
        severity:
          type: string
          enum:
            - info
            - opportunity
            - risk
          title: Severity
          default: info
        title:
          type: string
          title: Title
        detail:
          type: string
          title: Detail
        evidence_refs:
          items:
            type: string
          type: array
          title: Evidence Refs
      type: object
      required:
        - rule_id
        - module
        - panel
        - title
        - detail
      title: ModuleRuleFinding
      description: |-
        One deterministic finding emitted by the rule engine.

        Every LLM recommendation must cite one of these ``rule_id``s, so the
        narrative can neither contradict nor exceed the measured layer.
    ValidationError:
      properties:
        loc:
          items:
            anyOf:
              - type: string
              - type: integer
          type: array
          title: Location
        msg:
          type: string
          title: Message
        type:
          type: string
          title: Error Type
        input:
          title: Input
        ctx:
          type: object
          title: Context
      type: object
      required:
        - loc
        - msg
        - type
      title: ValidationError
    ModuleCoverageNearDuplicatePair:
      properties:
        domain_a:
          type: string
          title: Domain A
        domain_b:
          type: string
          title: Domain B
        edit_distance:
          type: integer
          title: Edit Distance
      type: object
      required:
        - domain_a
        - domain_b
        - edit_distance
      title: ModuleCoverageNearDuplicatePair
      description: |-
        One "these might be the same brand" hint (audit Tier 0.3).

        Two cohort domains within ``edit_distance`` of each other on their
        REGISTRABLE (eTLD+1) form — e.g. ``acme.com``/``acm3.com`` (a typo), or
        ``blog.acme.com``/``shop.acme.com`` (two subdomains of the same apex,
        both normalizing to ``acme.com``, distance 0). This is what closed the
        ``warbybarker.com`` vs ``warbyparker.com`` gap the audit's D5 finding
        named (distance 1, exact-string dedup never caught it).

        **Advisory only.** The audit's own phrasing is "surface, don't
        auto-merge" — no code path may read this field to combine, drop, or
        otherwise alter which domains belong to a cohort. It exists purely so a
        coverage strip can ask the operator/user "are these two the same
        brand?" instead of silently double-counting or silently guessing.
    SeoTableStakesKeyword:
      properties:
        keyword:
          type: string
          title: Keyword
        cohort_domains:
          type: integer
          title: Cohort Domains
          default: 0
        search_volume:
          anyOf:
            - type: integer
            - type: 'null'
          title: Search Volume
        brand_ranks:
          type: boolean
          title: Brand Ranks
          default: false
        brand_position:
          anyOf:
            - type: integer
            - type: 'null'
          title: Brand Position
      type: object
      required:
        - keyword
      title: SeoTableStakesKeyword
    SeoContentTypeMixRow:
      properties:
        content_type:
          type: string
          title: Content Type
        cohort_count:
          type: integer
          title: Cohort Count
          default: 0
        cohort_share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Cohort Share Pct
        brand_count:
          type: integer
          title: Brand Count
          default: 0
        brand_share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Brand Share Pct
      type: object
      required:
        - content_type
      title: SeoContentTypeMixRow
    SeoKeywordIntentMixRow:
      properties:
        intent:
          type: string
          enum:
            - informational
            - navigational
            - commercial
            - transactional
          title: Intent
        keyword_count:
          type: integer
          title: Keyword Count
          default: 0
        share_pct:
          anyOf:
            - type: number
            - type: 'null'
          title: Share Pct
      type: object
      required:
        - intent
      title: SeoKeywordIntentMixRow
    SeoGapKeyword:
      properties:
        keyword:
          type: string
          title: Keyword
        competitor_domains:
          type: integer
          title: Competitor Domains
          default: 0
        best_position:
          anyOf:
            - type: integer
            - type: 'null'
          title: Best Position
        search_volume:
          anyOf:
            - type: integer
            - type: 'null'
          title: Search Volume
        cpc:
          anyOf:
            - type: number
            - type: 'null'
          title: Cpc
        example_domain:
          anyOf:
            - type: string
            - type: 'null'
          title: Example Domain
      type: object
      required:
        - keyword
      title: SeoGapKeyword
    SeoWeaknessKeyword:
      properties:
        keyword:
          type: string
          title: Keyword
        competitor_domain:
          type: string
          title: Competitor Domain
        competitor_position:
          anyOf:
            - type: integer
            - type: 'null'
          title: Competitor Position
        brand_position:
          anyOf:
            - type: integer
            - type: 'null'
          title: Brand Position
        position_delta:
          anyOf:
            - type: integer
            - type: 'null'
          title: Position Delta
        search_volume:
          anyOf:
            - type: integer
            - type: 'null'
          title: Search Volume
      type: object
      required:
        - keyword
        - competitor_domain
      title: SeoWeaknessKeyword
  securitySchemes:
    HTTPBearer:
      type: http
      scheme: bearer

````