Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.tryprofound.com/llms.txt

Use this file to discover all available pages before exploring further.

The Profound app’s “Compare across models” view shows the same metric split by which AI surface served the answer. Same pattern works for region and persona. Add the segmentation field to dimensions (or use it as a filter to slice to one value).

How this example works

  1. Add the segmentation field to dimensions along with asset_name. You get one row per (segment, asset).
  2. Filter to your asset so the response is one row per segment.
  3. Sort by score to rank the segments.
import os
from profound import Profound

client = Profound(api_key=os.environ["PROFOUND_API_KEY"])

# What to fetch — replace with your own values.
CATEGORY_NAME = "<your-category-name>"
ASSET_NAME    = "<your-asset-name>"
START_DATE    = "2026-05-05"
END_DATE      = "2026-05-12"
SEGMENT       = "model"   # or "region", "persona"


def get_visibility_by_segment(category_id, asset_name, segment, start_date, end_date):
    """Visibility Score for one asset, broken down by `segment` (model/region/persona)."""
    res = client.reports.visibility(
        category_id=category_id,
        start_date=start_date,
        end_date=end_date,
        metrics=["visibility_score"],
        dimensions=[segment],
        filters=[{"field": "asset_name", "operator": "is", "value": asset_name}],
    )
    m_order = res.info.query["metrics"]
    d_order = res.info.query["dimensions"]
    i_score   = m_order.index("visibility_score")
    i_segment = d_order.index(segment)
    return sorted(
        [(row.dimensions[i_segment], row.metrics[i_score]) for row in res.data],
        key=lambda x: x[1],
        reverse=True,
    )


# Helpers — translate human-readable names into the IDs the report API needs.

def find_category_id(name):
    """Return the UUID of the category whose name matches (case-insensitive)."""
    for c in client.organizations.categories.list():
        if c.name.lower() == name.lower():
            return c.id
    raise ValueError(f"No category named {name!r}")


def find_asset_name(category_id, name):
    """Return the canonical asset name (case-insensitive) inside the category."""
    for a in client.organizations.categories.assets(category_id):
        if a.name.lower() == name.lower():
            return a.name
    raise ValueError(f"No asset named {name!r} in this category")


# Resolve names → IDs, then run.
category_id = find_category_id(CATEGORY_NAME)
asset_name  = find_asset_name(category_id, ASSET_NAME)

rows = get_visibility_by_segment(category_id, asset_name, SEGMENT, START_DATE, END_DATE)
print(f"{asset_name} Visibility Score by {SEGMENT}:")
for segment, score in rows:
    print(f"  {segment:<24} {score:.1%}")

Slicing to a single segment instead

If you only want the score for one model (say, “where do I stand on ChatGPT specifically?”), drop model from dimensions and use it as a filter:
filters=[
    {"field": "asset_name", "operator": "is", "value": "<your-asset-name>"},
    {"field": "model",      "operator": "is", "value": "gpt-4o"},
]
Now the response is one row — same shape as the headline recipe, scoped to ChatGPT.