"},
{"field": "model", "operator": "is", "value": "gpt-4o"},
]
```
Now the response is one row — same shape as the [headline
recipe](/cookbook/visibility/asset-visibility-score), scoped to ChatGPT.
# Visibility over time
Source: https://docs.tryprofound.com/cookbook/visibility/visibility-over-time
Build the daily, weekly, or monthly Visibility line chart for one asset.
The line chart on every Visibility tile in the Profound app is one call with
the `date` dimension added. Use `date_interval` to switch between day, week,
and month buckets.
**Don't average daily rows to derive a period score** — they're computed
differently. See [Conventions & gotchas](/cookbook/setup/conventions#don%E2%80%99t-average-daily-rows-to-get-a-period-score).
## How this example works
1. **Add `date` to dimensions and set `date_interval`** (`"day"` / `"week"`
/ `"month"`). One row per bucket. Different bucket sizes give different
numbers — see [Headline + daily](/cookbook/visibility/headline-and-daily).
2. **Filter by asset** so each bucket is one row.
3. **Read positions from `info.query`** instead of hardcoding them.
```python Python theme={null}
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 = ""
ASSET_NAME = ""
START_DATE = "2026-05-05"
END_DATE = "2026-05-12" # exclusive — returns data through 2026-05-11
DATE_INTERVAL = "day" # or "week" / "month"
def get_visibility_over_time(category_id, asset_name, start_date, end_date, interval="day"):
"""Daily/weekly/monthly Visibility Score for one asset, sorted by date."""
res = client.reports.visibility(
category_id=category_id,
start_date=start_date,
end_date=end_date,
metrics=["visibility_score"],
dimensions=["date"],
date_interval=interval,
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_date = d_order.index("date")
points = [
(row.dimensions[i_date], row.metrics[i_score])
for row in res.data
]
points.sort(key=lambda p: p[0])
return points # → [("2026-05-05", 0.78), ("2026-05-06", 0.81), ...]
# 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)
points = get_visibility_over_time(category_id, asset_name, START_DATE, END_DATE, DATE_INTERVAL)
for date, score in points:
print(f"{date} {score:.1%}")
```
```bash curl theme={null}
export PROFOUND_API_KEY=your_api_key_here
curl -X POST "https://api.tryprofound.com/v1/reports/visibility" \
-H "X-API-Key: $PROFOUND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"category_id": "your-category-uuid",
"start_date": "2026-05-05",
"end_date": "2026-05-12",
"metrics": ["visibility_score"],
"dimensions": ["date"],
"date_interval": "day",
"filters": [
{"field": "asset_name", "operator": "is", "value": ""}
]
}'
```
## Switching the bucket
Swap `date_interval` to roll the data up to coarser buckets:
| `date_interval` | What you get |
| --------------- | ----------------------------------------- |
| `"day"` | One point per calendar day (Eastern Time) |
| `"week"` | One point per ISO week |
| `"month"` | One point per calendar month |
The number of returned rows scales with the bucket size for the same window.
# AEM Integration Setup Guide
Source: https://docs.tryprofound.com/integrations/adobe-experience-manager/setup/aem-setup-guide
This guide walks you through connecting Adobe Experience Manager (AEM) as a Cloud Service to Profound using an Adobe OAuth Server-to-Server credential. Once connected, Profound Agents can access, create, and update the Content Fragment models, folders, and content allowed by the credential's AEM permissions.
## Before you start
You'll need:
* An [AEM as a Cloud Service](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/overview/introduction) program and **Author** environment
* [AEM Cloud Manager](https://experience.adobe.com/#/cloud-manager) access to commit to an Adobe-managed repository and run a config pipeline (**Deployment Manager** role required)
* Permissions to manage product profiles in the [Adobe Admin Console](https://adminconsole.adobe.com/) and to create OAuth credentials in the [Adobe Developer Console](https://developer.adobe.com/console)
* A [Profound](https://www.tryprofound.com/) account
## Setup guide
* Open [Adobe Cloud Manager](https://experience.adobe.com/#/cloud-manager).
* Sign in under the organization that owns the AEM program you intend to use with Profound.
* Select and open the program, then select **Environments** in the left sidebar.
* Open the environment you intend to use and copy its base **Author URL**. It should look like: `https://author-p12345-e67890.adobeaemcloud.com`.
To enable API access in your environment, follow [Adobe's AEM APIs setup guide](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/setup).
Once done, confirm that you have the correct product profile to use with the AEM API:
* Go back to your AEM program environment page in [Adobe Cloud Manager](https://experience.adobe.com/#/cloud-manager) (where you left off in [Step 1](#step-1)).
* Open the environment's action menu and select **Manage Access** > **Author Profiles**. [Adobe Admin Console](https://adminconsole.adobe.com/) opens your environment's page.
* Confirm that the **AEM Sites Content Managers - author...** profile exists for your program and environment.
To authenticate with Profound, create an OAuth credential. You, or anyone with a **Developer** role in your **AEM Sites Content Managers** product profile, can create it.
To assign a **Developer** role to the credential creator, continue where you left off in [Step 2](#step-2):
* On your environment's page in [Adobe Admin Console](https://adminconsole.adobe.com/), select the **AEM Sites Content Managers - author...** product profile.
* Open the **Developers** tab, then select **Add developers**.
* Add the email or username of the person creating the OAuth credential, then select **Save**.
Learn more about assigning developers to Adobe product profiles in Adobe's [Manage developers in Adobe Admin Console](https://helpx.adobe.com/enterprise/using/manage-developers.html) guide.
* Open the [Adobe Developer Console](https://developer.adobe.com/console). If you're following these steps in sequence, you should already be signed in under the organization that owns your Author AEM environment (same as in [Step 1](#step-1)).
* Select **Create new project** in the **Quick start** section, or go to **Projects** in the top navigation menu and select **Create new project**.
* On the project page, select **Edit project**, give your project a descriptive name (such as **Profound integration credentials**), then select **Save**.
* Select **Add to Project** > **API**.
* On the **Add an API** page, filter the API list by **Experience Cloud**, select **AEM CS Sites Content Management**, then select **Next**.
* Select **Server-to-Server** > **OAuth Server-to-Server** as the authentication type.
* Select the Author product profile you prepared in [Step 2](#step-2), then save the configuration.
The AEM Sites Content Management API also provides the folder access Profound uses. No additional credentials are required.
After you save the API configuration, [Adobe Developer Console](https://developer.adobe.com/console) returns you to the project page. In the **Credentials** section, select your new OAuth Server-to-Server credential. From the credential page, copy the values you need to create the AEM integration in Profound:
* **Client ID**
* **Client Secret**
* **Scopes** — copy the complete value exactly as Adobe displays it
* **Organization ID** — optional; copy it only if the AEM tenant requires the `x-gw-ims-org-id` header
Before you can use the credential, register its client ID with your Author environment.
* Back in [Adobe Cloud Manager](https://experience.adobe.com/#/cloud-manager), open the program and select **Repositories** in the left sidebar.
* Identify the Adobe-managed repository and branch used by your environment's config pipeline.
* Select **Access Repo Info** and copy the repository URL and access credentials.
* Using your regular development workflow, clone the repository onto your machine and create or update the `config/api.yaml` file in the root directory with the following configuration:
```yaml theme={null}
kind: "API"
version: "1"
metadata:
envTypes: ["dev", "stage", "prod"]
data:
allowedClientIDs:
author:
- ""
```
Replace `` with the client ID you copied from Developer Console in [Step 5](#step-5).
If you already have other API credentials configured, keep the existing configuration and add the client ID to the `author` list under `allowedClientIDs`.
Learn more about managing repositories and configuring pipelines in the following Adobe resources:
* [AEM API client ID registration guide](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/developing/open-api-based-apis#registering-a-client-id)
* [Manage repositories in Cloud Manager](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/using-cloud-manager/managing-code/managing-repositories)
* [Use config pipelines](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/operations/config-pipeline) guide
* [Invoke OpenAPI-based AEM APIs using OAuth Server-to-Server authentication](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/invoke-api-using-oauth-s2s) tutorial
* Still on your program page in [Adobe Cloud Manager](https://experience.adobe.com/#/cloud-manager), select **Pipelines** in the left sidebar.
* Select **Add Pipeline**, then select **Add Non-Production Pipeline** for the development environment, or **Add Production Pipeline** for stage and production.
* In the **Add Pipeline** dialog, select **Deployment Pipeline**, give your pipeline a descriptive name, then select **Continue**.
* On the next screen, fill in the values as follows:
* Select code to deploy: **Targeted deployment**
* Include: **Config**
* Eligible Deployment Environments: select your AEM environment from the dropdown
* Repository, Git Branch, Code Location: the repository, branch, and config directory from [Step 6](#step-6)
* Select **Save**.
Your new config pipeline appears in the list of pipelines in the **Pipelines** section. Select the pipeline, then select **Run selected**. Wait for the deployment to complete successfully.
Learn more about deploying config pipelines in the following Adobe resources:
* [Use config pipelines](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/operations/config-pipeline) guide
* [Cloud Manager CI/CD pipelines](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/using-cloud-manager/cicd-pipelines/introduction-ci-cd-pipelines) overview
* In [Profound](https://platform.tryprofound.com), go to **Integrations** in the left sidebar.
* Search for **Adobe Experience Manager (S2S)** and select it.
* In the Adobe Experience Manager (S2S) integration view, select **+ Add account**.
* In the **Connect Adobe Experience Manager (S2S)** dialog, enter the Author URL from [Step 1](#step-1) and the client secret, client ID, scopes, and organization ID you retrieved in [Step 5](#step-5).
* Select **Connect account**.
If the connection succeeds, your AEM environment appears in the list of connected accounts.
Revoke Profound's access to your AEM environment at any time by selecting **Revoke** in the integration account action menu.
To make sure Profound has all the permissions it needs to work with your AEM environment, verify that the AEM Agent nodes run successfully.
* In [Profound](https://platform.tryprofound.com), [create a new Agent](https://help.tryprofound.com/articles/2212787792-create-an-agent), or open an existing Agent draft.
* Add the Adobe Experience Manager **List Content Fragments** and **Get Content Fragment** nodes, then select the connected AEM instance.
* Select **Test node** (a play icon) in the node configuration panel and confirm that the AEM output contains the expected data.
* If you intend to create or update content fragments with Profound Agents, test the **Create Content Fragment** and **Update Content Fragment** nodes the same way.
Delete test content directly in the AEM environment. Current Profound Agent nodes don't include a delete operation.
## Rotating AEM credentials
### Rotate a client secret only
Adobe supports two client secrets on one OAuth Server-to-Server credential, which allows rotation without changing the client ID.
Rotate your client secret as instructed in [Adobe developer documentation](https://developer.adobe.com/developer-console/docs/guides/authentication/ServerToServerAuthentication/implementation#rotating-client-secrets), then update the credentials in Profound (**Integrations** > **Adobe Experience Manager (S2S)** > **Edit credentials** in a connected account's action menu).
The client ID doesn't change during this process, so you don't need to update or redeploy `api.yaml`.
### Rotate the entire OAuth credential
To replace the entire AEM OAuth credential:
1. Generate a new credential as described in [Step 4](#step-4) of the setup guide.
2. Deploy the new client ID in `config/api.yaml` as instructed in [Step 6](#step-6) of the setup guide.
3. Update the credentials in Profound.
Keep the old client ID registered until you've verified the new connection.
## Best practices
* Use an **Author** environment only. Profound doesn't connect to AEM Publish or Preview. Learn more about environments in [AEM as a Cloud Service tutorials](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/cloud-manager/environments).
* Test the read and write Profound Agent nodes separately to verify their folder and repository permissions.
* Always store your client secret and other credentials in an approved secret manager, and never include them in screenshots, tickets, or source control.
# Troubleshooting AEM Integration Setup
Source: https://docs.tryprofound.com/integrations/adobe-experience-manager/setup/aem-setup-troubleshooting
## OAuth Server-to-Server authentication method is not available
Confirm that the credential creator is assigned as a **Developer** on the intended product profile and that the profile includes the AEM Sites service, as described in [Step 2](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-2) and [Step 3](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-3) of the setup guide.
## AEM CS Sites Content Management product profile is missing
Go back to [Step 2](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-2) of the setup guide and verify the following:
* Your Adobe organization owns the AEM environment you intend to use with Profound.
* The environment is modernized for API access as instructed in Adobe's [Set up OpenAPI-based AEM APIs](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/setup) guide.
## Profound can't save the AEM credentials
Confirm the following:
* All connection values are correct and match the values of your OAuth credential from [Step 5](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-5) of the setup guide.
* Your OAuth credential uses the **AEM Sites Content Managers - author...** product profile. Check this in the [Adobe Developer Console](https://developer.adobe.com/console). If it doesn't, repeat [Step 2](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-2) of the setup guide.
* The config pipeline that deploys your API configuration (`api.yaml`) ran successfully. Check the **Pipelines** section of your AEM program page in [Adobe Cloud Manager](https://experience.adobe.com/#/cloud-manager). If it didn't, repeat [Step 6](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-6) and [Step 7](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-7) of the setup guide.
* The client ID of the OAuth credential is in the correct place in the `api.yaml` configuration file, as instructed in [Step 6](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-6) of the setup guide.
* An Author IP allowlist isn't blocking Profound. Learn more in Adobe's [Manage IP Allow Lists](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/using-cloud-manager/ip-allow-lists/managing-ip-allow-lists) guide.
If you have to apply an Author IP allowlist, contact Profound Support to obtain the current Profound outbound IP addresses rather than reusing values from an old guide or ticket.
* If you're using a sandbox environment, it's online and not hibernated. Learn more in Adobe's [Hibernate and De-Hibernate Sandbox Environments](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/implementing/using-cloud-manager/programs/hibernating-environments) guide.
## Content Fragment Models don't appear in Profound
This usually means either the Content Fragment Model isn't allowed for the folders you use with Profound, or your OAuth credential's technical account lacks the permissions to manage Content Fragment Model configuration.
Confirm the following:
* The Content Fragment Model is enabled and allowed on your assets folder. Learn more in Adobe's [Content Fragment Models](https://experienceleague.adobe.com/en/docs/experience-manager-65/content/assets/content-fragments/content-fragments-models#enabling-disabling-a-content-fragment-model) documentation.
* The technical account's service group has permissions to manage the Content Fragment Model configuration. With the setup described in the [setup guide](/integrations/adobe-experience-manager/setup/aem-setup-guide#setup-guide), your technical account should already have the necessary permissions to read and manage your AEM content. If it doesn't, manage permissions for specific folders and files in your AEM environment as described in Adobe's [Product Profile and Services user group permission management](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/how-to/services-user-group-permission-management) guide.
Grant the AEM OAuth credential's technical account the narrowest permissions that support the Agent nodes you intend to use in Profound. Scope create and update access to approved folders only.
## Folders don't appear in Profound
* Go back to [Step 5](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-5) of the setup guide and confirm that the **Scopes** connection value for your Profound AEM integration matches the scopes value of your AEM OAuth credential.
* Confirm that the scopes value includes `aem.fragments.management` and `aem.folders`. If it doesn't, don't add the missing scopes by hand. Confirm instead that you completed all prerequisites in [Step 2](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-2) and [Step 3](/integrations/adobe-experience-manager/setup/aem-setup-guide#step-3) of the setup guide.
* Confirm that the technical account's service group has the permissions it needs to manage content in the `/content/dam` folder in your AEM environment. To add permissions for specific folders and files, follow Adobe's [Product Profile and Services user group permission management](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/how-to/services-user-group-permission-management) guide.
## Create or Update Content Fragment node returns a permissions error
This usually means your AEM OAuth credential is authenticated but doesn't have the required repository access. Follow Adobe's [Product Profile and Services user group permission management](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/how-to/services-user-group-permission-management) guide to grant the service group that contains your AEM technical account the create or update permissions it needs for the folder you use with Profound.
# Using Adobe Experience Manager in Agents
Source: https://docs.tryprofound.com/integrations/adobe-experience-manager/using-adobe-experience-manager-in-agents
After you connect your Adobe Experience Manager (AEM) account, the following nodes become available in Profound Agents. Use them to find, read, create, and update AEM Content Fragments. All operations run against the connected AEM Author environment and use the permissions assigned to the OAuth credential's technical account.
## Available nodes
### List Content Fragments
Retrieve Content Fragments from the connected Author environment.
#### Required inputs
* **AEM Instance** — the connected Author environment
#### Optional inputs
* **Folder** — limits the list to an approved folder below `/content/dam`
* **References** — controls whether linked fragments are returned and hydrated
* **Limit** — number of results to return; the default is `25` and the maximum is `50`
* **Cursor** — a pagination cursor from a previous List or Search node's output, used to fetch the next page of results
* **Projection** — use `summary` when you need summary data only
#### Output
The output contains the matching Content Fragments and, when more results are available, a pagination cursor for the next page.
### Search Content Fragments
Find Content Fragments matching one or more criteria.
#### Required inputs
* **AEM Instance** — the connected Author environment
Profound starts the search with a **Folder** filter of `/content/dam`. Change that folder or add another filter as needed.
#### Search filters
* **Search text** — searches the AEM-supported fragment content for the selected text
* **Folder** — scopes the search to a DAM folder path
* **Models** — limits results to selected Content Fragment Models
* **Statuses** — New, Draft, Published, Modified, or Unpublished
* **Locale** — limits results to a locale
* **Direct children only** — excludes fragments in nested folders
* **Created after** and **Created before** — constrain the creation date
#### Optional inputs
* **Raw Query** — an AEM-supported search-query JSON; use it for filters or sorting the node configuration form doesn't include
* **Limit** — number of results to return; the default is `25` and the maximum is `50`
* **Cursor** — a pagination cursor from a previous List or Search node's output, used to fetch the next page of results
* **Projection** — use `summary` when you need summary data only
#### Output
The output contains the matching Content Fragments and, when more results are available, a pagination cursor for the next page.
### Get Content Fragment
Retrieve the complete data for one Content Fragment.
#### Required inputs
* **AEM Instance** — the connected Author environment
* **Content Fragment** — select a fragment from the dropdown, or use a variable from a previous node's output
#### Optional inputs
* **Content Fragment ID** — the fragment UUID as text, which overrides the fragment selected in [required inputs](#required-inputs)
* **References** — controls whether linked fragments are returned and hydrated
#### Output
The output includes the Content Fragment data and its ETag when available. Model-specific fields follow the response AEM returns.
### Create Content Fragment
Add Author content based on an enabled Content Fragment Model.
#### Required inputs
* **AEM Instance** — the connected Author environment
* **Parent Folder** — the destination folder below `/content/dam`
* **Content Fragment Model** — the model that defines the fragment fields
* **Title** — the fragment title
* **Data format**
* **Structured** — loads the selected model and displays its fields in the configuration panel
* **Raw JSON** — accepts an object whose keys match the AEM model's field names
* **Fields** / **Raw JSON** — the structure for your input data, based on the selected **Data format**
Use Raw JSON when the Content Fragment Model is supplied with a variable, because the node editor can't load that model's field definition in advance.
#### Optional inputs
* **Name** — URL-safe Content Fragment name; derived from the **Title** when left blank
* **Description** — fragment description
#### Output
The output includes the created Content Fragment, its ETag, and its Location when AEM provides those values.
Creating or updating a fragment doesn't publish it. Review and publish the content in AEM.
### Update Content Fragment
Change an existing fragment. The node modifies only the fields you provide.
#### Required inputs
* **AEM Instance** — the connected Author environment
* **Content Fragment** — select a fragment from the dropdown, or use a variable from a previous node's output
* **Data format**
* **Structured** — loads the selected model and displays its fields in the configuration panel
* **Raw JSON** — accepts an object whose keys match the AEM model's field names
* At least one change to **Title**, **Description**, or **Fields** / **Raw JSON**
Use Raw JSON when the Content Fragment Model is supplied with a variable, because the node editor can't load that model's field definition in advance.
#### Optional inputs
* **Title** — leave empty to keep the current title
* **Description** — leave empty to keep the current description
* **Fields** / **Raw JSON** — the structure for your input data, based on the selected **Data format**
* **References** — controls whether linked fragments are returned and hydrated
* **ETag** — optimistic-lock value from an earlier Get or Update output. When left blank, Profound reads the current ETag immediately before sending the update. If the provided ETag is stale, the node reports a conflict.
#### Output
The output includes the updated Content Fragment and its new ETag when AEM provides one.
Creating or updating a fragment doesn't publish it. Review and publish the content in AEM.
***
## Key concepts
### AEM Instance
The connected AEM Author environment. Select it before choosing a model, folder, or fragment.
### Content Fragment Model
The AEM schema that defines a fragment's fields, types, required values, and allowed content. The model must be enabled and allowed by the destination folder's policy.
### DAM paths
Content Fragment folders use repository paths below `/content/dam`. Folder permissions and policies control which content Profound can read or change.
### Content Fragment ID
AEM API operations identify a Content Fragment by UUID. Profound's picker displays searchable fragment information and supplies the UUID to the node.
### ETag
An ETag is a unique identifier for a specific version of a Content Fragment's data. Pass it from a **Get Content Fragment** node to the **Update Content Fragment** node to prevent the workflow from silently overwriting a change made after the fragment was read.
### Pagination
List and Search nodes return up to `50` fragments per request. When the output contains a cursor, provide it to the next List or Search node to retrieve the next page of results.
### Hydrated Content Fragment
A Content Fragment that contains its full field values, rather than only basic IDs and URLs.
### References
References control how linked fragments are included. Hydrated and all-reference modes can return larger responses, so use them only when the workflow needs linked content.
***
## Troubleshooting
### A folder, fragment, or model picker is disabled or empty
Select an **AEM Instance** first. If the picker stays empty, verify that your OAuth credential's technical account can read the corresponding model, folder, or fragment. Learn more in the [setup troubleshooting](/integrations/adobe-experience-manager/setup/aem-setup-troubleshooting) guide.
### Search returns an invalid-query error
Restore the **Folder** filter to `/content/dam` or add another filter. When using **Raw Query**, include a non-empty JSON object and use Adobe-supported filter and sort fields.
### Create node reports an unknown field or invalid value
Select the model and use **Structured** format when possible. If you have to use **Raw JSON** format, make sure each key matches the AEM model field name and provide a value with the model's expected type and cardinality.
### Update node reports that there are no changes
Enter at least one **Title**, **Description**, or model field value. Empty inputs preserve the current content.
### Update node reports a conflict
The fragment changed after AEM issued the ETag. Run the **Get Content Fragment** node again, review the latest content, then apply the update with the new ETag.
### A node returns a permissions error
Confirm that the technical account's service group has permission for that exact operation and DAM path. Read access can succeed while Create or Update remains blocked. To add permissions for specific folders and files in your AEM environment, follow Adobe's [Product Profile and Services user group permission management](https://experienceleague.adobe.com/en/docs/experience-manager-learn/cloud-service/aem-apis/openapis/how-to/services-user-group-permission-management) guide.
### Only the first page of results is returned
Use the cursor returned by the List or Search node as the next request's **Cursor**. Each page can contain no more than `50` results.
***
## Additional resources
* [AEM Sites Content Management API reference](https://developer.adobe.com/experience-cloud/experience-manager-apis/api/stable/sites/)
* [AEM Folders API reference](https://developer.adobe.com/experience-cloud/experience-manager-apis/api/stable/folders/)
# Connect Contentful to Profound
Source: https://docs.tryprofound.com/integrations/contentful/connect-contentful-to-profound
## Prerequisites
Before connecting Contentful to Profound, ensure:
* You have access to your Contentful organization
* You have **Admin** or **Owner** permissions for the space you want to connect
* Your Contentful account is active
## Connect Your Account
1. In Profound, go to **Account → Integrations → Contentful**.
2. Click **Connect account**.
3. You'll be redirected to Contentful to authorize Profound.
4. Sign in to your Contentful account and grant the requested permissions.
5. Select the organization and space you want to connect.
6. Once authorized, you'll be redirected back to Profound.
Once connected, Contentful will appear as an available integration and can be selected inside Agents.
Profound requests **content\_management\_manage** scope, which allows creating, updating, and publishing content in your connected spaces.
# Using Contentful in Agents
Source: https://docs.tryprofound.com/integrations/contentful/using-contentful-in-agents
After connecting your Contentful account, the following actions become available as Agent steps. Each step requires you to select a connected **Contentful Account** from a dropdown.
#### **Create Entry**
Create a new entry in your Contentful space.
**Required inputs**
* **Contentful Account**
* **Space**
* **Environment**
* **Content Type**
* **Fields** (dynamic based on content type schema)
**Optional inputs**
* **Locale** (defaults to space's default locale)
* **Publish** (publish immediately or save as draft)
The entry is created based on your content type's schema. Rich text fields accept Markdown which is automatically converted to Contentful's rich text format.
**Tip:** Leave **Publish** unchecked to create drafts for review before publishing.
#### **Update Entry**
Update an existing entry in your Contentful space.
**Required inputs**
* **Contentful Account**
* **Space**
* **Environment**
* **Entry ID**
**Optional inputs**
* **Fields** (only fields you want to update)
* **Locale** (defaults to space's default locale)
* **Publish** (publish changes immediately)
**Important:** Only the fields you provide will be modified; all other fields remain unchanged.
#### **Get Entry**
Retrieve a single entry by ID.
**Required inputs**
* **Contentful Account**
* **Space**
* **Environment**
* **Entry ID**
The output includes the entry's full content with all fields and metadata.
#### **List Entries**
Retrieve a list of entries from your Contentful space.
**Required inputs**
* **Contentful Account**
* **Space**
* **Environment**
**Optional inputs**
* **Content Type** (filter by content type)
* **Limit** (number of entries to return)
* **Skip** (pagination offset)
The output is a structured list of entries that can be used in downstream Agent steps.
***
## Supported Field Types
Contentful's dynamic schema means Profound automatically adapts to your content model. All field types are supported:
| Field Type | Description | Input Format |
| --------------- | ---------------------- | ------------------------- |
| **Short text** | Single-line text | Plain text |
| **Long text** | Multi-line text | Plain text |
| **Rich text** | Formatted content | Markdown (auto-converted) |
| **Number** | Decimal numbers | Number |
| **Integer** | Whole numbers | Integer |
| **Boolean** | True/false | Boolean |
| **Date & time** | ISO 8601 dates | Date string |
| **Location** | Geographic coordinates | `{lat, lon}` object |
| **JSON object** | Arbitrary JSON | JSON object |
| **Media** | Asset references | Asset ID |
| **Reference** | Entry references | Entry ID or array of IDs |
***
## Working with Rich Text
Rich text fields in Contentful use a structured document format (AST). Profound accepts **Markdown**, **HTML**, or **Contentful's native rich text JSON** format.
**Supported Markdown:**
* Headings (`# H1` through `###### H6`)
* Paragraphs
* **Bold**, *italic*, and other formatting
* Bullet and numbered lists
* Blockquotes
* Code blocks
* Links
**Supported HTML:**
* `` through `` headings
* `
` paragraphs
* ``, ``, `` formatting
* ``, ``, `- ` lists
* `
` blockquotes
* ``, `` code blocks
* `` links
**Native Rich Text JSON:**
If you already have Contentful rich text documents, you can pass them directly:
```json theme={null}
{
"nodeType": "document",
"data": {},
"content": [
{
"nodeType": "paragraph",
"data": {},
"content": [
{ "nodeType": "text", "value": "Hello world", "marks": [] }
]
}
]
}
```
**Tip:** Use whichever format is most convenient for your workflow. Markdown, HTML, and native rich text JSON all work seamlessly.
***
## Working with References
Reference fields link entries together. You can provide:
* **Single reference**: Just the entry ID as a string
* **Multiple references**: An array of entry IDs
Profound automatically compiles these into Contentful's required link format.
***
## Understanding Locales
Contentful uses a locale-based content model where every field value is keyed by locale (e.g., `en-US`, `fr-FR`). Profound handles this automatically:
* **Default behavior**: If you don't specify a locale, Profound uses your space's default locale
* **Single locale**: Specify a locale to write content in that language
* **Multi-locale**: Use the raw JSON format to write multiple locales at once
When you provide a simple field value like:
```json theme={null}
{
"title": "My Blog Post"
}
```
Profound automatically wraps it for Contentful's API:
```json theme={null}
{
"title": {
"en-US": "My Blog Post"
}
}
```
This locale wrapping happens for all fields before submission to Contentful.
***
## Input Formats
Profound accepts two input formats for creating and updating entries:
The simple format is human-friendly and handles locale wrapping automatically:
```json theme={null}
{
"space": "your-space-id",
"environment": "master",
"content_type_id": "blogPost",
"locale": "en-US",
"fields": {
"title": "My Blog Post",
"body": "# Hello\n\nThis is **markdown**.",
"heroImage": "asset-123",
"relatedPosts": ["post-1", "post-2"]
},
"publish": false
}
```
**Features:**
* Flat field structure (no locale nesting)
* Simple string IDs for references
* Markdown for rich text fields
* Automatic locale wrapping
The raw format gives you full control over locale-specific content:
```json theme={null}
{
"space": "your-space-id",
"environment": "master",
"content_type_id": "blogPost",
"fields": {
"title": {
"en-US": "My Blog Post",
"fr-FR": "Mon Article de Blog"
},
"body": {
"en-US": "# Hello\n\nEnglish content.",
"fr-FR": "# Bonjour\n\nContenu français."
}
},
"publish": false
}
```
**Use this format when:**
* Writing content in multiple locales simultaneously
* You need precise control over locale-specific values
* Migrating content from another system
***
## Common Use Cases
* **Content Publishing**: Generate and publish blog posts, articles, or product descriptions
* **Content Updates**: Bulk update existing entries with new information
* **Content Migration**: Move content between environments or spaces
* **Automated Workflows**: Create entries based on external triggers or data sources
***
## Additional Resources
Learn more about Contentful's content model and API:
* [Contentful Content Model Concepts](https://www.contentful.com/developers/docs/concepts/data-model/) - Understanding spaces, environments, and content types
* [Contentful Localization](https://www.contentful.com/developers/docs/concepts/locales/) - How locales work in Contentful
* [Rich Text Field Type](https://www.contentful.com/developers/docs/concepts/rich-text/) - Understanding Contentful's rich text format
* [Content Management API](https://www.contentful.com/developers/docs/references/content-management-api/) - Full API reference
# Connect Drupal to Profound
Source: https://docs.tryprofound.com/integrations/drupal/connect-drupal-to-profound
This guide walks you through connecting your Drupal account to Profound. Once connected, Profound Agents can access, edit, and manage your Drupal content directly.
## Before you start
You'll need:
* [Drupal](https://www.drupal.org/) account with an administrator role, or any other role that allows you to administer users and permissions (learn more in Drupal's [Roles and Permissions documentation](https://www.drupal.org/docs/roles-and-permissions))
* A public Drupal HTTPS website
* [JSON:API](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module) Drupal core module: it powers every action Profound performs
* [JSON:API Permission Access](https://www.drupal.org/project/jsonapi_permission_access) module to enable API authentication access for select user roles
* [Key auth](https://www.drupal.org/project/key_auth) module to enable API key authentication that allows Profound to take actions on your behalf
* [Profound](https://www.tryprofound.com/) account
## Setup guide
* In Drupal, navigate to **Configuration > Web Services > JSON:API**.
* Enable **Accept all JSON:API create, read, update, and delete operations**.
* Select **Save configuration**.
* In the Drupal platform, navigate to **People** in the left sidebar and select **+ Add user**.
* Name the user `profound`, give it a **Content editor** role or any other role with content management permissions, and select **Create new account**.
* Once the user is created, it appears on the user list.
To allow Profound to authenticate with Drupal using an API key, enable **Access JSON:API** and **Use key authentication** permissions for the role you assigned to your Profound user.
* In Drupal, navigate to **People > Permissions**.
* Search for the relevant permission and enable it for the role your Profound user has.
* Select **Save permissions**.
A standard Drupal content editor role has sufficient content permissions for Profound to perform the necessary actions. If you want to review or customize content permissions for Profound, you can do so anytime in the **Permissions** view in Drupal.
* Navigate to **People** and select `profound` user you created in [Step 2](#step-2).
* Append `/key-auth` to the user page URL. For example:
```text theme={null}
https://your-site.com/user/5/key-auth
```
* On the key authentication page for the user, select **Generate new key**.
* Save the API key in a secure place, you'll need it to set up the integration in Profound.
Now that you have everything you need, create a Drupal integration in the Profound platform:
* Navigate to **Integrations** in the left sidebar.
* Search for **Drupal** and select it.
* In the Drupal integration view, select **+ Add account**.
* In the **Connect Drupal** dialog, enter the API key you generated in [Step 4](#step-4) and your Drupal website's base URL.
* Select **Connect Account**.
If your Drupal account appears in the list of connected accounts, the integration was successful and is ready to use with Profound.
Revoke Profound's access to your Drupal account anytime by selecting **Revoke** in the integration account action menu.
You can also connect your Drupal account to Profound directly in the Agent builder view. Navigate to **Agents > + Create new**, add one of the Drupal nodes to the canvas, select it to open its configuration panel, and follow the **Connect account** flow.
## Best practices
* Make sure your Drupal website is public and uses HTTPS. Profound rejects non-HTTPS websites.
* To customize permissions specifically for the Profound Drupal user, consider creating a custom role for it. Learn more in the Drupal [Roles and Permissions](https://www.drupal.org/docs/roles-and-permissions#s-create-a-custom-role) documentation.
* When reviewing Profound user permissions, grant it permissions only for the content you intend Profound to use.
* Always store your API keys in a secure place, such as secure notes in your password manager.
## Troubleshooting
### There is no JSON:API permission in my Drupal Permissions view
Check that the JSON:API Permission Access module is installed in your Drupal platform:
* Navigate to **Extend** in the left sidebar.
* If the module is installed, it appears on the module list with a selected checkbox.
* If it's not on the list, install it via the **Browse modules** tab.
### I see "We couldn't save these credentials" error in Profound
When connecting your Drupal account to Profound, you may see this error:
```txt wrap theme={null}
We couldn't save these credentials
Drupal JSON:API is reachable without a valid API key. Configure JSON:API to require key authentication.
```
It likely means that you're missing either the [JSON:API Permission Access](https://www.drupal.org/project/jsonapi_permission_access) module in Drupal or the **Access JSON:API** permission for your Profound user.
If that's the case, install the module and enable the permission as instructed in [Step 3](#step-3).
# Using Drupal in Agents
Source: https://docs.tryprofound.com/integrations/drupal/using-drupal-in-agents
After connecting your Drupal account, the following nodes become available in Profound Agents.
The nodes work with Drupal's [JSON:API](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module) module. Content is accessed by a **resource type** (the entity type, such as Basic, Image, or Article) and by a **resource UUID**.
## Available nodes
### Create Item
Create a new item of a resource type.
#### Required inputs
* **Drupal Site** — Select a site from the dropdown
* **Resource type** — The JSON:API resource type, such as `node--article`
* **Attributes** or **Relationships** (or both) — A JSON object of field values or references to other resources.
A request with neither Attributes nor Relationships is rejected, include at least one.
### Update Item
Update an existing item.
#### Required inputs
* **Drupal Site** — Select a site from the dropdown
* **Resource type** — The JSON:API resource type, such as `node--article`
* **Resource UUID**
* **Attributes** or **Relationships** (or both) — A JSON object of field values or references to update. At least one is required.
Only the attributes and relationships you provide are modified.
### Get Item
Retrieve a single item.
#### Required inputs
* **Drupal Site** — Select a site from the dropdown
* **Resource type** — The JSON:API resource type, such as `node--article`
* **Resource UUID**
The output includes the item's full content with attributes, relationships, and metadata from the JSON:API response.
### List Items
List items of a given resource type.
#### Required inputs
* **Drupal Site** — Select a site from the dropdown
* **Resource type** — The JSON:API resource type, such as `node--article`
#### Optional inputs: Query options
* **Filter** — A JSON object using Drupal JSON:API filter syntax
* **Fields** — The fields to return per object in the node output; if nothing is specified, all fields are returned
* **Include** — A list of the related entities to include in the output (learn more in the [JSON:API documentation](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module/includes))
* **Sort** — Sort expression for the result set
* **Limit** — Number of items to return (default 25, up to 50)
* **Offset** — Pagination offset (default 0)
The output is a structured list of items that can be used in downstream workflow steps.
***
## Key concepts
### Resource types
Resource types follow Drupal's JSON:API naming convention: the entity type and bundle joined by two hyphens.
| Resource type | Description |
| --------------------- | -------------------------- |
| `node--article` | Article content type nodes |
| `node--page` | Basic page nodes |
| `taxonomy_term--tags` | Tags taxonomy terms |
Use **List Items** to discover available resource types and inspect the structure of items returned for your Drupal site.
### Resource UUIDs
Items are referenced by **UUID**. When you create or list items, use the UUID from the JSON:API response as the **Resource UUID** in later steps.
### Attributes and relationships
**Create Item** and **Update Item** require at least one of **Attributes** or **Relationships**.
* **Attributes** — Field values for the item, such as title, body, or status. Example attributes for a `node--article`:
```json theme={null}
{
"title": "My new article",
"body": {
"value": "Article content here.
",
"format": "basic_html"
},
"status": true
}
```
* **Relationships** — References to other resources, such as taxonomy terms, authors, or related nodes.
Example relationships linking tags to an article:
```json theme={null}
{
"field_tags": {
"data": [
{ "type": "taxonomy_term--tags",
"id": "9b2c3d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e"
}
]
}
}
```
***
## Additional resources
* [Drupal's JSON:API module documentation](https://www.drupal.org/docs/core-modules-and-themes/core-modules/jsonapi-module)
* [JSON:API specification](https://jsonapi.org/format/)
# Connect Framer to Profound
Source: https://docs.tryprofound.com/integrations/framer/connect-framer-to-profound
## Prerequisites
Before connecting Framer to Profound, ensure:
* You have access to the Framer project you want Profound to manage
* You have generated a Framer API key for that project
* You have the Framer project URL for the project you want to connect
1. Open the Framer project you want to connect.
2. Go to **Site Settings → General**.
3. Create a new API key for the project.
4. Copy the API key and store it securely.
1. Open the Framer project you want to connect.
2. While viewing the Framer editor/project page, copy the project URL from your browser's address bar.
Use a project URL like:
```text theme={null}
https://framer.com/projects/
```
Do **not** use your deployed or published site URL, for example:
```text theme={null}
https://your-site-name.framer.website
```
## Connect Your Account
1. In Profound, go to **Account → Integrations → Framer**.
2. Click **Connect account**.
3. Enter your **Framer API Key**.
4. Enter your **Framer Project URL**.
5. Click **Connect account** to finish.
Once connected, Framer will appear as an available integration and can be selected inside Agents.
Framer API keys are bound to a single project. If you want to use multiple Framer sites in Profound, connect each project separately.
# Using Framer in Agents
Source: https://docs.tryprofound.com/integrations/framer/using-framer-in-agents
This page covers the **Framer CMS** integration in Profound.
After connecting your Framer project, the following actions become available as Agent steps for working with Framer CMS collections and items. Each step requires you to select a connected **Framer Project** from a dropdown.
#### **Create Item**
Create a new CMS item in a Framer collection.
**Required inputs**
* **Framer Project** — Select the Framer project you connected in Profound from the dropdown
* **Collection** — Select the collection from the dropdown
* **Field Data** — The available fields are generated from the selected collection's schema. See [Working with Create Item Inputs](#working-with-create-item-inputs).
The output includes the created item's `id`, `slug`, `draft`, and [`field_data`](#understanding-item-output).
**Tip:** Use **Get Collection** first to inspect the collection schema and confirm which fields are required before creating an item.
#### **List Collections**
Retrieve the CMS collections available in your connected Framer project.
**Required inputs**
* **Framer Project** — Select the Framer project you connected in Profound from the dropdown
The output includes a structured list of collections with each collection's `id`, `name`, and `readonly` values.
#### **Get Collection**
Retrieve a single Framer collection and its schema.
**Required inputs**
* **Framer Project** — Select the Framer project you connected in Profound from the dropdown
* **Collection** — Select the collection from the dropdown
The output includes the collection's `id`, `name`, `readonly`, `managed_by`, and [`field_definitions`](#understanding-collection-schemas), which describe each field's `id`, `name`, `type`, and whether it is required.
#### **List Items**
Retrieve CMS items from a Framer collection.
**Required inputs**
* **Framer Project** — Select the Framer project you connected in Profound from the dropdown
* **Collection** — Select the collection from the dropdown
The output includes each item's `id`, `slug`, `draft`, and [`field_data`](#understanding-item-output).
#### **Get Item**
Retrieve a single CMS item by ID.
**Required inputs**
* **Framer Project** — Select the Framer project you connected in Profound from the dropdown
* **Collection** — Select the collection from the dropdown
* **Item ID** — Enter the item ID directly
The output includes the item's `id`, `slug`, `draft`, and [`field_data`](#understanding-item-output) so it can be inspected or passed to later steps.
***
## Supported Field Types
Framer's dynamic schema means Profound adapts to your collection model. The following Framer CMS field types are currently supported when creating items:
| Field Type | Description | Supported |
| ------------------- | --------------------------- | --------- |
| **Plain Text** | Single-line text | Yes |
| **Formatted Text** | Rich text content | Yes |
| **Date** | Date field | No |
| **Link** | URL field | Yes |
| **Image** | Image asset | No |
| **Gallery** | Array of images | No |
| **Color** | Color value | No |
| **Toggle** | True/false value | Yes |
| **Number** | Numeric value | Yes |
| **Option** | Single-select option | Yes |
| **File** | File asset | No |
| **Reference** | Reference to another item | No |
| **Multi-Reference** | Reference to multiple items | No |
***
## Understanding Collection Schemas
Use **Get Collection** to inspect a collection's schema before working with its items.
The output includes:
* **Collection ID** and **Collection Name**
* **readonly** — whether the collection is read-only
* **managed\_by** — how the collection is managed
* **field\_definitions** — the fields configured on that collection
Each field definition includes:
* **id** — the field's internal Framer ID
* **name** — the label shown in Framer
* **type** — the field's primary Framer type, such as `string`, `formattedText`, or `number`
* **required** — whether the field is required
* **itemType** — additional item information for compound field types when Framer provides it
Example collection output:
```json theme={null}
{
"collection": {
"field_definitions": [
{
"id": "slug",
"name": "Slug",
"required": true,
"type": "string",
"itemType": null
},
{
"id": "111111",
"name": "Title",
"required": true,
"type": "string",
"itemType": null
},
{
"id": "222222",
"name": "Content",
"required": true,
"type": "formattedText",
"itemType": null
}
],
"id": "333333",
"managed_by": "user",
"name": "Example Collection",
"readonly": false
}
}
```
***
## Working with Create Item Inputs
When you select a Framer collection in **Create Item**, Profound renders inputs dynamically from that collection's schema.
For supported field types, you can fill in the values directly in the step UI. For example, a collection may expose fields such as:
* **Slug**
* **Title**
* **Content**
* **Link**
* **Name**
* **Option**
* **Count**
* **Featured**
If a collection includes required fields with unsupported types, the **Create Item** request will fail because Profound cannot provide values for those fields.
**Note:** Use **Get Collection** to confirm the field definitions before creating an item. If you need support for a Framer field type that is not currently supported, contact us and we can help evaluate your use case.
***
## Understanding Item Output
Framer item responses include top-level item fields such as:
* **id**
* **slug**
* **draft**
* **field\_data**
The `field_data` object is keyed by field ID. Each entry includes the field's human-readable name, type, and value.
Example item output:
```json theme={null}
{
"item": {
"draft": true,
"field_data": {
"111111": {
"name": "Title",
"type": "string",
"value": "Example title",
"valueByLocale": {}
},
"222222": {
"name": "Featured",
"type": "boolean",
"value": true
}
},
"id": "333333",
"slug": "example-title"
}
}
```
***
## Common Use Cases
* **Content Publishing**: Create new Framer CMS items from AI-generated copy or structured data
* **Content Retrieval**: Pull structured content from Framer collections for review, summarization, or downstream workflows
* **Workflow Preparation**: Inspect collection schemas before building automations that depend on specific Framer fields
# Connect G2 to Profound
Source: https://docs.tryprofound.com/integrations/g2/connect-g2-to-profound
This guide walks you through connecting your G2 account to Profound. Once connected, Profound Agents and Aim can access, edit, and manage your G2 data directly.
## Before you start
You'll need:
* [G2](https://www.g2.com/) vendor account
* [Profound](https://www.tryprofound.com/) account
## Setup guide
To locate the G2 integration in the Profound platform:
* Navigate to **Integrations** in the left sidebar.
* Search for **G2** and select it.
Depending on your needs, set up a G2 integration, a G2 connector, or both.
This is a one-time setup. After you connect your G2 account, it remains available for future use until you [revoke access](#revoking-access).
### G2 integration
The G2 integration allows Profound Agents and Sheets to work with your G2 data.
* In the G2 integration view, navigate to the **Integration** tab.
* Select **+ Add account**.
Follow the pop-up dialog that prompts you to sign in to your G2 account and authorize Profound to access your account.
If your G2 account appears in the list of connected accounts, the connection was successful and is ready to use with Profound.
You can also connect your G2 account to Profound directly in the Agent builder view. Navigate to **Agents** > **+ Create new**, add one of the G2 nodes to the canvas, select it to open its configuration panel, and follow the **Connect account** flow.
### G2 connector
The G2 connector allows Aim to access your G2 data and use it in conversations live.
* In the G2 integration view, navigate to the **Connector** tab.
* Select **+ Add account**.
Follow the pop-up dialog that prompts you to sing in to your G2 account and share authentication with Profound.
If your G2 account appears in the list of connected accounts, the connection was successful and is ready to use with Profound.
Review the permissions you want to give Profound Aim for the tools available with the G2 connector in the **Tools & permissions** table.
Each tool has three options:
* **Allow**: Aim can use the tool anytime
* **Ask**: Aim will ask you before using the tool
* **Block**: Aim can't use the tool
The tools that can cause irreversible deletions or edits are listed in the **Destructive tools** section. Block these tools by default or set them to **Ask**.
## Revoking access
Revoke Profound's access to your G2 account anytime by selecting Revoke in the integration account action menu.
Revoke access separately for the integration and the connector.
# Using G2 in Agents
Source: https://docs.tryprofound.com/integrations/g2/using-g2-in-agents
After connecting your G2 account, the following nodes become available in Profound Agents. G2 Agent nodes bring buyer intent, market signals, reviews, ratings, and review excerpts into Agents.
## Available nodes
### Browse Buyer Intent
Surfaces G2 accounts showing active buying intent for one or more products.
#### Required inputs
* **G2 Account** — Select an account from the dropdown
#### Optional inputs
* **Products** — One or more products to track, entered as a product slug, product ID, or G2 product URL
* **Dimensions** — Which intent dimensions to include. **Company Name** and **Company Domain** are selected by default. Other options include Company Country, Employees, Industry, Signal Type, Provider, as well as other product, category, vendor, and visitor dimensions
* **Start date** / **End date** — The date range to pull intent data for (`YYYY-MM-DD`)
* **Company name** — Filter results to a specific company, for example `Acme`
* **Company domain** — Filter results to a specific company by domain, for example `example.com`
* **Signal type** — Narrow results to one kind of intent signal: Profile, Category, Compare, Competitors, Ad, Product Reference Page, Licensed Content, Vendors, Pricing, Competitive Profile, Competitive Compare, or Competitive Pricing
* **Minimum intent score** — Only return results with an intent score at or above this value (`0`–`100`)
* **Limit** — Maximum number of results to return. Defaults to `100` (max `100`)
* **Pagination cursor** — Pass a cursor from a previous response's `next_cursor` to fetch the next page of results
#### Output
The output is a JSON object with accounts showing buyer intent signals on G2, plus metadata that includes the next pagination cursor.
### Get Market Signals
Returns market intent activity for one or more G2 categories over a date range.
#### Required inputs
* **G2 Account** — Select an account from the dropdown
* **Categories** — One or more G2 categories to pull market signals for
#### Optional inputs
* **Start date** / **End date** — The date range to pull signals for (`YYYY-MM-DD`)
* **Limit** — Maximum number of results to return. Defaults to `100` (max `100`)
* **Pagination cursor** — Pass a cursor from a previous response's `next_cursor` to fetch the next page of results
#### Output
The output is a JSON object with market intent signals for the selected categories, plus metadata that includes the next pagination cursor.
### Get Reviews
Pulls G2 reviews for a product.
#### Required inputs
* **G2 Account** — Select an account from the dropdown
* **Product** — A single product, entered as a product slug, product ID, or G2 product URL
#### Optional inputs
* **Submitted after** / **Submitted before** — Limit results to reviews submitted in a date range
* **Minimum star rating** — Only return reviews with a rating at or above this value (`1`–`5`)
* **Limit** — Maximum number of results to return. Defaults to `100` (max `100`)
* **Pagination cursor** — Pass a cursor from a previous response's `next_cursor` to fetch the next page of results
#### Output
The output is a JSON object with reviews for the product, plus metadata that includes the next pagination cursor.
### Get Product Rating
Returns a product's G2 rating scores.
#### Required inputs
* **G2 Account** — Select an account from the dropdown
* **Product** — A single product, entered as a product slug, product ID, or G2 product URL
#### Output
The output is a JSON object with G2 rating records for the product, including ease of use, ease of setup, direction, and other satisfaction sub-scores.
### Get Review Snippets
Returns short, quotable excerpts from G2 reviews.
#### Required inputs
* **G2 Account** — Select an account from the dropdown
* **Product** — A single product, entered as a product slug, product ID, or G2 product URL
#### Optional inputs
* **NPS bucket** — Net Promoter Score category: `promoter`, `passive`, or `detractor`
* **Company segment** — For example, `Mid-Market`
* **Industry** — For example, `SaaS`
* **Categories** — Narrow snippets to one or more G2 categories
* **Role** — Narrow snippets to reviewers with a specific role, for example `CTO`
* **Tags** — Narrow snippets to one or more tags, for example `onboarding`
#### Output
The output is a JSON object with short review excerpts for the product.
Snippets are separate from the full reviews feed. G2 may return zero snippets for a product that still has reviews. Use **Get Reviews** when you need the full review text.
***
## Key concepts
### Product identifiers
Product fields accept a **product slug**, **product ID**, or **G2 product URL**. Use the same identifier in every G2 node in an Agent so results describe the same product throughout the run.
### Filters and optional fields
Optional fields act as filters. When left empty, the node returns unfiltered data.
### Pagination
Nodes that return lists default to a maximum of `100` results. To fetch more, pass the previous response's `next_cursor` into **Pagination cursor** on the next run or step.
# Connect Gamma to Profound
Source: https://docs.tryprofound.com/integrations/gamma/connect-gamma-to-profound
## Prerequisites
Before connecting Gamma to Profound, ensure:
* You have a [Gamma](https://gamma.app) account with API access
* You have generated an API key from Gamma
1. Visit the [Gamma developer documentation](https://developers.gamma.app/docs/get-access) for instructions on requesting API access
2. Once approved, generate an API key from your Gamma account settings
3. Copy and store the API key securely — you'll need it when connecting to Profound
## Connect Your Account
1. In Profound, go to **Account → Integrations → Gamma**.
2. Click **Connect account**.
3. Enter your **Gamma API Key**.
4. Provide a **Workspace Name** — a friendly label to identify this Gamma connection.
5. Click **Save** to complete the setup.
Once connected, Gamma will appear as an available integration and can be selected inside Agents.
# Using Gamma in Agents
Source: https://docs.tryprofound.com/integrations/gamma/using-gamma-in-agents
After connecting your Gamma account, the following actions become available as Agent steps. Each step requires you to select a connected **Gamma Account** from a dropdown.
#### **Generate Content**
Create a new AI-powered presentation, document, or webpage from scratch.
**Required inputs**
* **Gamma Account**
* **Input Text** (the content or topic to generate from)
**Optional inputs**
* **Format** — `presentation`, `document`, `webpage`, or `social`
* **Text Mode** — how Gamma handles your input text:
* `generate` (default) — AI generates content based on your input
* `condense` — AI condenses your input into fewer cards
* `preserve` — AI preserves your input text as-is
* **Number of Cards** — how many slides/pages to generate
* **Additional Instructions** — extra guidance for the AI
* **Theme ID** — a Gamma theme to apply
* **Export As** — optionally export as `pdf` or `pptx`
**Text options**
* **Text Amount** — level of detail (e.g., `detailed`, `concise`)
* **Text Tone** — comma-separated tone descriptors (e.g., `friendly, professional`)
* **Text Audience** — target audience (e.g., `executives`, `students`)
* **Text Language** — output language (e.g., `en`, `es`, `fr`)
**Image options**
* **Image Source** — where to source images from: `ai_generated`, `unsplash`, `giphy`, `web_free_to_use`, `web_free_to_use_commercially`, `pictographic`, `placeholder`, or `no_images`
**Sharing options**
* **Workspace Access** — access level for workspace members:
* `workspace_default` — uses your workspace's default sharing settings
* `view` — members can view the content
* `comment` — members can view and leave comments
* `edit` — members can view, comment, and edit the content
* `full_access` — members have full control, including sharing and deletion
* **External Access** — access level for people outside the workspace (defaults to `no_access`):
* `no_access` — external users cannot access the content
* `view` — external users can view the content via a shared link
* `comment` — external users can view and leave comments
* `edit` — external users can view, comment, and edit the content
**Tip:** Generation is asynchronous — Profound automatically polls for completion before returning the result to subsequent Agent steps.
#### **Generate from Template**
Remix an existing Gamma template with new content.
**Required inputs**
* **Gamma Account**
* **Template ID** (the Gamma ID of the template to remix)
* **Prompt** (instructions and content to adapt the template with)
**Optional inputs**
* **Theme ID** — override the template's theme
* **Export As** — optionally export as `pdf` or `pptx`
* **Workspace Access** — access level for workspace members (see sharing options in Generate Content above)
* **External Access** — access level for external users (see sharing options in Generate Content above, defaults to `no_access`)
**Tip:** Templates are great for maintaining consistent branding. Create a template in Gamma, then use this action to generate variations with different content.
#### **Get Generation Status**
Check the status of a content generation.
**Required inputs**
* **Gamma Account**
* **Generation ID**
The output includes:
* **Status** — `pending`, `completed`, or `failed`
* **Gamma URL** — link to the generated content (available when completed)
* **Export URL** — link to the exported file if PDF/PPTX export was requested
**Note:** You typically don't need to use this step directly — Profound handles polling automatically when you use the Generate actions.
***
## Output Formats
Gamma can generate content in several formats:
| Format | Description |
| ---------------- | ---------------------------------------------------------- |
| **Presentation** | Slide-based format, similar to PowerPoint or Google Slides |
| **Document** | Long-form scrollable content |
| **Webpage** | Standalone shareable webpage |
| **Social** | Social media-optimized content |
You can also export the result as **PDF** or **PPTX** for offline use.
***
## Common Use Cases
* **Sales Decks**: Generate personalized presentations from CRM data or call transcripts
* **Reports**: Turn data and analysis into polished documents or presentations
* **Training Materials**: Create training decks from knowledge base content
* **Client Deliverables**: Generate branded documents from templates with client-specific content
* **Social Content**: Create social media visuals from blog posts or product updates
# Connect Gong to Profound
Source: https://docs.tryprofound.com/integrations/gong/connect-gong-to-profound
The Gong integration is not yet available. We expect to launch in the coming weeks.
**Technical Administrator Required**: Only users with the Technical Administrator role in Gong can authorize integrations. If you're not a tech admin, you'll need to ask your Gong administrator to complete this setup.
## Prerequisites
Before connecting Gong to Profound, ensure:
* You have **Technical Administrator** permissions in Gong
* Your Gong account is active and in good standing
1. Log in to Gong and click your name in the top right corner
2. Select **My Settings**
3. Scroll to the bottom of the page to see the list of Technical Administrators
4. Alternatively, go to **Company Settings → Team Members** and check your profile
If you're not listed as a Technical Administrator, contact someone who is to complete the integration setup.
## Connect Your Account
1. In Profound, go to **Account → Integrations → Gong**.
2. Click **Connect account**.
3. You'll be redirected to Gong to authorize Profound.
4. Sign in with your **Technical Administrator** account and grant the requested permissions.
5. Once authorized, you'll be redirected back to Profound.
Once connected, Gong will appear as an available integration and can be selected inside Agents.
# Using Gong in Agents
Source: https://docs.tryprofound.com/integrations/gong/using-gong-in-agents
The Gong integration is not yet available. We expect to launch in the coming weeks.
After connecting your Gong account, the following actions become available as Agent steps. Each step requires you to select a connected **Gong Account** from a dropdown.
#### **Get Call**
Retrieve a single call by ID with full details.
**Required inputs**
* **Gong Account**
* **Call ID**
**Optional inputs**
* **Include Transcript** (include full transcript structure)
The output includes comprehensive call data: metadata, participants, topics discussed, trackers detected, and optionally the full transcript.
#### **Get Transcript**
Retrieve the full transcript for a specific call.
**Required inputs**
* **Gong Account**
* **Call ID**
The output includes the complete transcript with:
* Speaker identification
* Timestamps for each segment
* Topic segmentation
* Full text of the conversation
**Tip:** Transcripts can be large for long calls. Use this action when you need the full conversation text for analysis or content generation.
***
## What Data is Available
Gong provides rich AI-analyzed conversation data:
| Data Type | Description |
| ----------------- | ----------------------------------------------------------------- |
| **Call Metadata** | Title, date, duration, participants, direction (inbound/outbound) |
| **Transcript** | Full text with speaker identification and timestamps |
| **Topics** | AI-detected topics discussed during the call |
| **Trackers** | Custom keyword and phrase detection (competitors, pricing, etc.) |
| **Talk Ratios** | Speaking time distribution between participants |
| **Questions** | Questions asked during the conversation |
***
## Common Use Cases
* **Content Generation**: Use call transcripts to generate blog posts, case studies, or training materials
* **Competitive Intelligence**: Monitor calls for competitor mentions and extract insights
* **Sales Coaching**: Analyze top-performing calls and create training content
* **CRM Updates**: Extract action items and next steps from calls to update your CRM
* **Knowledge Base**: Convert call transcripts into searchable documentation
# Connect Looker to Profound
Source: https://docs.tryprofound.com/integrations/looker/connect-looker-to-profound
[Looker](https://cloud.google.com/looker) is Google Cloud's enterprise business intelligence platform. Teams connect it to a data warehouse (BigQuery, Snowflake, Redshift, and others), define metrics in **LookML**, and use Looker's UI to explore data, build reports, and share dashboards.
This is **not** [Looker Studio](https://lookerstudio.google.com/) (formerly Google Data Studio). It is also **not** the same as Profound's Tableau connector, which exports Profound analytics into Tableau. Profound's Looker integration works in the opposite direction: **Profound Agents query data from your Looker instance**.
## What Looker terms mean
| Term | What it is |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **LookML** | Looker's modeling language. Analytics teams use it to define dimensions, measures, joins, and business logic on top of raw warehouse tables. |
| **Model** | A LookML project exposed for querying, such as `marketing` or `core`. Agent inline queries reference a model by name. |
| **Explore** | A starting point for ad hoc analysis within a model — a curated set of related tables and fields users can query. Inline queries need both a model and an explore name. |
| **Look** | A saved report or query in Looker. If your team already built the metric in Looker, agents can run it directly with **Run Look**. |
| **Dashboard** | A collection of Looks and visualizations. Profound does not embed dashboards; agents run individual Looks or inline queries and receive the underlying data. |
## What this integration does
Profound connects to **your** Looker instance using API credentials (`client_id`, `client_secret`, and instance URL). Once connected, Profound Agents can:
* **Run a saved Look** — execute an existing Look and return the result as JSON for downstream agent steps
* **Run an inline query** — query a specific model and Explore with custom fields, filters, sorts, and advanced options
The integration is **read-only** and **org-level**. Profound runs queries against Looker and returns the results; it does not create, update, or delete Looker content. One Looker connection is shared across your organization and can be selected in any agent that needs it.
## Where you can use Looker in Profound
| Surface | What it does |
| ------------------- | ----------------------------------------------------------------------------------------- |
| **Profound Agents** | Add **Run Look** or **Run Inline Query** steps to pull Looker data into an agent workflow |
| **Sheets** | Import rows from a saved Look into a spreadsheet for analysis or batch agent runs |
Both surfaces use the same org-level Looker connection and the same read-only query capabilities.
## Prerequisites
Before connecting Looker to Profound, ensure:
* You have access to a Google Cloud Looker instance (for example, `https://your-company.cloud.looker.com`)
* You can create or use a Looker user with API credentials
* That user has permission to access the saved Looks, models, Explores, and fields your agents will query
1. In Looker, go to **Admin → Users** and select the user Profound should use for API access
2. In the user's **API credentials** section, create a new API key pair
3. Copy the generated **Client ID** and **Client Secret** before leaving the page — Looker may not show the secret again
4. Confirm the user can access the Looks, models, Explores, dimensions, and measures your agents will need
## Connect Your Account
1. In Profound, go to **Account → Integrations → Looker**.
2. Click **Connect account**.
3. Enter your connection details:
* **Looker Base URL** — your instance URL, for example `https://your-company.cloud.looker.com`
* **Client ID** — the Looker API `client_id`
* **Client Secret** — the Looker API `client_secret`
4. Click **Save**.
Profound validates the credentials by authenticating with Looker (Looker API 4.0) and confirming the API user. Once connected, Looker appears as an available integration in Agents and Sheets.
## Troubleshooting
Confirm the base URL is the root Looker instance URL, such as `https://your-company.cloud.looker.com`. Profound also accepts URLs that include `/api` or `/api/4.0` and normalizes them to the root instance URL.
Make sure the Looker API user has access to the folders and saved Looks you expect to use. If permissions were recently changed, retry after a short delay.
Check the Looker user's role, model set, and field-level permissions. Profound can only run queries that the connected Looker user is allowed to run.
# Using Looker in Agents
Source: https://docs.tryprofound.com/integrations/looker/using-looker-in-agents
After connecting your Looker account, the following actions become available as Agent steps. Each step requires you to select a connected **Looker Account** from a dropdown.
Profound pulls **query results** from Looker — rows of metrics and dimensions your analytics team has already modeled — not Looker dashboards or visualizations. Results are returned as structured data (typically JSON) that later agent steps can summarize, compare, or combine with other integrations.
## Available actions
| Action | What it does |
| -------------------- | ----------------------------------------------------------------------------------------- |
| **Run Look** | Executes a saved Look by ID and returns the result |
| **Run Inline Query** | Builds and runs a query against a model, Explore, and field list you specify in the agent |
#### **Run Look**
Execute a saved Look from your Looker instance and return the result as structured data.
**Required inputs**
* **Looker Account**
* **Look** — a saved Look from the selected account. The dropdown loads Looks from Looker and shows each Look's title with its ID.
**Optional inputs**
* **Result Format** — the format returned by Looker. Defaults to `json_bi`, which is recommended for downstream agent steps.
* **Row Limit** — maximum number of rows to return.
**Output**
* **Look Results** — a JSON value containing the returned Looker result.
**Tip:** Use **Run Look** when the query already exists as a saved Look in Looker. This keeps business logic governed in Looker and is the safest option for recurring agent automations.
#### **Run Inline Query**
Run a query against a specific Looker model and Explore with fields, filters, sorts, and advanced query options.
**Required inputs**
* **Looker Account**
* **Model** — the Looker model name, such as `marketing`
* **Explore** — the Explore name, such as `web_event`
* **Fields** — comma-separated Looker fields, such as `web_event.date, web_event.unique_users`
**Optional inputs**
* **Sorts** — comma-separated sorts, such as `web_event.date desc`
* **Row Limit** — maximum rows to return. Defaults to `500`.
* **Result Format** — defaults to `json_bi`
**Advanced inputs**
* **Filter Expression** — Looker filter expression using `${field}` syntax
* **Pivots** — comma-separated fields to pivot on
* **Subtotals** — comma-separated fields to subtotal on
* **Fill Fields** — comma-separated fields to fill missing rows for, usually date fields
* **Dynamic Fields** — JSON string for table calculations or custom dimensions
* **Column Limit** — maximum number of columns to return
* **Total** — whether Looker should include totals
* **Row Total** — row total type, such as `right`
* **Query Timezone** — optional IANA timezone, such as `America/Los_Angeles`
* **Server Table Calcs** — whether table calculations should run on the server
* **Apply Formatting** — whether Looker formatting should be applied to the result
**Output**
* **Query Results** — a JSON value containing the returned Looker result.
**Tip:** Use field names exactly as they appear in Looker, including the `view.field` prefix. For date filters, use Looker filter syntax from your LookML model (for example, `30 days` on a date field).
***
## What data is available
Query results depend on the Look or Explore you run. In general, Looker returns the fields defined in your LookML model:
| Data type | Description |
| ---------------------- | -------------------------------------------------------------------------------------- |
| **Dimensions** | Attributes you group or filter by, such as date, channel, region, or product |
| **Measures** | Aggregated metrics, such as revenue, session count, conversion rate, or unique users |
| **Filters & sorts** | Applied at query time — either baked into a saved Look or specified in an inline query |
| **Totals & subtotals** | Optional row or column totals when enabled on inline queries |
Profound returns the raw query result as structured data (typically JSON). Your agent or sheet decides what to do with it — summarize it, compare periods, or pass rows to another step.
## Supported result formats
Both actions support multiple Looker result formats. **`json_bi`** is the default and recommended format for agent workflows because it returns structured JSON that downstream steps can parse reliably.
Other supported formats: `json`, `csv`, `txt`, `html`, `md`, `xlsx`, `sql`, `png`, and `jpg`. Use non-JSON formats only when a later step explicitly needs that output type.
## Limits
* **Run Inline Query** defaults to **500 rows** and supports up to **5,000 rows** per run.
* **Run Look** supports an optional row limit override up to **5,000 rows**.
* The connected Looker user's permissions still apply — Profound cannot return data the API user cannot access.
***
## Choosing an action
| Use **Run Look** when… | Use **Run Inline Query** when… |
| ------------------------------------------------------------- | --------------------------------------------------------- |
| The query is already saved and approved in Looker | The agent needs dynamic fields, filters, or date windows |
| You want Looker to remain the source of truth for query logic | You are building parameterized reporting inside the agent |
| You need a simple, governed recurring report | Earlier agent steps determine which metrics to fetch |
***
## Common use cases
* Pull a saved traffic or revenue Look into a weekly summary agent
* Fetch governed KPIs from Looker and pass them to a content-generation step
* Run dynamic inline queries with date windows that change based on agent inputs
* Combine Looker metrics with data from other integrations in a single agent
* Import a saved Look into a Sheet to analyze metrics alongside agent-generated columns
***
## Best practices
* Prefer `json_bi` for downstream agent steps because it returns structured data
* Start with a saved Look when possible; use inline queries only when the agent needs dynamic logic
* Keep row limits focused so later steps receive only the data they need
* Make sure the connected Looker user has access to every model, Explore, field, and Look used by the agent
***
## Common errors
The Look dropdown depends on the selected Looker account. Choose a **Looker Account** before selecting a saved Look.
The connected Looker user may not have access to any saved Looks, or the Looks may be in folders the user cannot access.
Inline queries must use Looker model, Explore, and field names exactly as they exist in Looker.
Profound uses the connected Looker API user. Update that user's Looker role, model set, or folder permissions if the agent cannot access the requested data.
# Connect Sanity to Profound
Source: https://docs.tryprofound.com/integrations/sanity/sanity
## Prerequisites
Before connecting Sanity to Profound, ensure:
* You have a [Sanity.io](https://www.sanity.io) account with an active project
* You have **Editor** or **Administrator** permissions on the project
* You have generated an API token with write access
## Generate a Sanity API Token
1. Go to your [Sanity project management console](https://www.sanity.io/manage).
2. Select your project.
3. Navigate to **API → Tokens**.
4. Click **Add API token**.
5. Give the token a descriptive name (e.g., "Profound Integration").
6. Set the permissions to **Editor** (minimum required).
7. Click **Save** and copy the token.
**Important:** Copy the token immediately — it won't be shown again. Store it securely.
## Find Your Project ID
Your Project ID is displayed at the top of your project's management console, or in the URL: `https://www.sanity.io/manage/project/`.
## Connect Your Account
1. In Profound, go to **Account → Integrations → Sanity**.
2. Click **Connect account**.
3. Enter your **API Token** and **Project ID**.
4. Click **Save**.
Once connected, Sanity will appear as an available integration and can be selected inside Agents.
Profound requires a token with **Editor** permissions at minimum. Tokens with read-only (Viewer) access will not work for creating or updating documents.
# Using Sanity in Agents
Source: https://docs.tryprofound.com/integrations/sanity/using-sanity-in-agents
After connecting your Sanity account, the following actions become available as Agent steps. Each step requires you to select a connected **Sanity Project** from a dropdown.
#### **Create Resource**
Create a new document in your Sanity dataset.
**Required inputs**
* **Sanity Project** — Select the Sanity project you connected in Profound
* **Dataset** — Select the dataset (e.g., `production`)
* **Document Details** — A JSON object with your document fields (must include `_type`)
**Optional inputs**
* **Rich Text Content** — A JSON object mapping field names to HTML strings. Profound automatically converts HTML to Sanity's Portable Text format
* **Publish Resource** — Check this to publish immediately, or leave unchecked to create a draft
By default, new documents are created as **drafts**. Profound automatically generates a draft ID prefixed with `drafts.` for you. Enable **Publish Resource** to make the document live immediately.
**Tip:** Leave **Publish Resource** unchecked to create drafts for review in Sanity Studio before publishing.
#### **Update Resource**
Update an existing document in your Sanity dataset.
**Required inputs**
* **Sanity Project** — Select the Sanity project you connected in Profound
* **Dataset** — Select the dataset
* **Resource ID** — The Sanity document ID to update
* **Update Details** — A JSON object with the fields you want to change
**Optional inputs**
* **Rich Text Content** — A JSON object mapping field names to HTML strings, auto-converted to Portable Text
**Important:** Only the fields you provide will be modified; all other fields remain unchanged. The document's `_type` cannot be changed after creation.
#### **Get Resource**
Retrieve a single document by ID.
**Required inputs**
* **Sanity Project** — Select the Sanity project you connected in Profound
* **Dataset** — Select the dataset
* **Resource ID** — The Sanity document ID to fetch
The output includes the document's full content with all fields and metadata. Both published and draft documents can be retrieved (drafts use the `drafts.` prefix).
#### **List Resources**
Retrieve a list of documents from your Sanity dataset.
**Required inputs**
* **Sanity Project** — Select the Sanity project you connected in Profound
* **Dataset** — Select the dataset
**Optional inputs**
* **Document Type** — Filter by a specific Sanity document type, or leave as "All Types"
* **Include drafts?** — Uses the raw perspective to include both published and draft documents
* **Page** — Page number to retrieve (defaults to 1)
* **Per Page** — Number of items per page (defaults to 100)
The output is a structured list of documents ordered by creation date (newest first) that can be used in downstream Agent steps.
#### **Publish Resource**
Publish a draft document to make it live.
**Required inputs**
* **Sanity Project** — Select the Sanity project you connected in Profound
* **Dataset** — Select the dataset
* **Draft ID** — The draft document ID to publish (must start with `drafts.`)
Publishing replaces the published version with the draft content and removes the draft document. This mirrors the publish behavior in Sanity Studio.
***
## Key Concepts
### Documents and Types
Every document in Sanity has a `_type` field that determines its schema. Sanity types are the equivalent of "content models" or "templates" — they define the structure and fields a document can have.
When creating a document with the **Create Resource** step, the `_type` field in your data determines which schema the document follows. The type must already exist in your Sanity project's schema.
Common examples of document types:
| Type | Example Use |
| ---------- | ----------------------- |
| `post` | Blog articles |
| `page` | Static pages |
| `product` | E-commerce products |
| `author` | Content creators |
| `category` | Taxonomy/classification |
**Tip:** To see which types exist in your project, use the **List Resources** step without a type filter — the returned documents will show the available `_type` values.
### Datasets
Sanity projects can have multiple datasets (e.g., `production`, `staging`, `development`). Each dataset is an independent content store. Always specify the correct dataset when configuring your Agent steps.
### Drafts vs. Published
Sanity uses a dual-ID system for content versioning:
* **Published documents** have a plain ID (e.g., `abc123`)
* **Draft documents** have the same ID prefixed with `drafts.` (e.g., `drafts.abc123`)
When you create a resource without enabling **Publish Resource**, Profound automatically creates it as a draft. You can later publish it using the **Publish Resource** step, or publish directly from Sanity Studio.
***
## Working with Portable Text (Rich Text)
Sanity uses [Portable Text](https://www.sanity.io/docs/block-content) as its native rich text format. Portable Text is a JSON-based specification that represents structured content as an array of blocks.
### Providing Rich Text Content
You have two options for providing rich text content to Sanity fields:
Use the **Rich Text Content** field to pass HTML strings. Profound automatically converts them to Portable Text blocks.
Map field names to HTML strings:
```json theme={null}
{
"body": "Welcome
This is a blog post with formatting.
"
}
```
**Supported HTML elements:**
| Element | Portable Text equivalent |
| ---------------------- | ------------------------- |
| `` through `` | Heading styles |
| `
` | Normal paragraph |
| ``, `` | Bold mark |
| ``, `` | Italic mark |
| `` | Underline mark |
| `` | Code mark |
| `` | Link annotation |
| ``, ``, `- ` | Bullet and numbered lists |
| `
` | Blockquote style |
| `
` | Line break |
**Tip:** This is the easiest way to get rich text into Sanity. Generate HTML from an LLM step and pass it directly to Rich Text Content — Profound handles the conversion.
If you already have Portable Text JSON (for example, from a **Get Resource** step), you can pass it directly in the **Document Details** field:
```json theme={null}
{
"_type": "post",
"title": "My Post",
"body": [
{
"_type": "block",
"_key": "abc123",
"style": "normal",
"markDefs": [],
"children": [
{
"_type": "span",
"_key": "def456",
"marks": [],
"text": "Hello world"
}
]
}
]
}
```
Each block requires:
* `_type`: Always `"block"` for text blocks
* `_key`: A unique string identifier
* `style`: Block style (`"normal"`, `"h1"` through `"h6"`, `"blockquote"`)
* `markDefs`: Array of complex mark definitions (e.g., links with `href`)
* `children`: Array of spans with `_type`, `_key`, `text`, and `marks`
Formatting marks include: `"strong"`, `"em"`, `"underline"`, `"code"`.
For list items, add:
* `listItem`: `"bullet"` or `"number"`
* `level`: Nesting level (integer)
***
## Mapping Sanity Schemas to Agent Steps
If you have an existing Sanity schema (document type), here's how to map it to a **Create Resource** step in your Agent.
### Example: Blog Post Schema
Suppose your Sanity Studio has a `post` type with these fields:
```js theme={null}
// In your Sanity Studio schema
defineType({
name: 'post',
title: 'Post',
type: 'document',
fields: [
defineField({ name: 'title', type: 'string' }),
defineField({ name: 'slug', type: 'slug' }),
defineField({ name: 'author', type: 'reference', to: [{ type: 'author' }] }),
defineField({ name: 'body', type: 'blockContent' }),
defineField({ name: 'publishedAt', type: 'datetime' }),
defineField({ name: 'categories', type: 'array', of: [{ type: 'reference', to: [{ type: 'category' }] }] }),
],
})
```
### Step-by-Step Setup
1. **Add a Create Resource step** to your Agent and select your connected Sanity project from the **Sanity Project** dropdown.
2. **Select the Dataset** from the dropdown (e.g., `production`).
3. **Fill in Document Details** with your document fields as JSON. This is where you provide simple values like titles, slugs, references, and categories:
```json theme={null}
{
"_type": "post",
"title": "My Post Title",
"slug": {
"_type": "slug",
"current": "my-post-title"
},
"author": {
"_type": "reference",
"_ref": "author-id-123"
},
"publishedAt": "2025-01-15T10:30:00Z",
"categories": [
{
"_type": "reference",
"_ref": "category-id-456"
}
]
}
```
To use dynamic values from upstream steps, type `/` inside the field to open the variable menu and select a variable. It will appear as a pill badge inline with your JSON — for example, you could replace `"My Post Title"` with a variable from a previous LLM step.
4. **Fill in Rich Text Content** for any Portable Text fields (like a blog body). Map the field name to an HTML string — Profound converts it to Sanity's format automatically:
```json theme={null}
{
"body": "Welcome
This is my post content.
"
}
```
You can also insert a variable here to pass in HTML generated by a previous step. Type `/` to open the variable menu and select the output from an LLM or other upstream step as the value.
5. **Check or uncheck Publish Resource** — check it to publish immediately, or leave it unchecked to create a draft for review in Sanity Studio.
**Tip:** Any text field in the node settings supports **variables** — type `/` to open the variable menu and insert outputs from upstream steps. Variables appear as interactive pill badges and are resolved at runtime.
### Field Type Reference
| Sanity Field Type | JSON Format in Data |
| --------------------- | --------------------------------------------------------------------------------------------- |
| `string` | `"value"` |
| `text` | `"multi-line value"` |
| `number` | `42` |
| `boolean` | `true` / `false` |
| `datetime` | `"2025-01-15T10:30:00Z"` |
| `date` | `"2025-01-15"` |
| `url` | `"https://example.com"` |
| `slug` | `{ "_type": "slug", "current": "my-slug" }` |
| `reference` | `{ "_type": "reference", "_ref": "document-id" }` |
| `image` | `{ "_type": "image", "asset": { "_type": "reference", "_ref": "image-asset-id" } }` |
| `blockContent` | Use **Rich Text Content** field for automatic conversion, or pass Portable Text JSON directly |
| `array` of references | `[{ "_type": "reference", "_ref": "id" }]` |
| `object` | `{ "fieldA": "value", "fieldB": 42 }` |
***
## Common Workflows
### Generate and Publish a Blog Post
1. **LLM Step** — Generate a title, slug, and HTML body from a prompt
2. **Create Resource** — Create a Sanity `post` document using the generated content
3. **Publish Resource** — Publish the draft (or set `publish_resource: true` in step 2)
### Update Existing Content
1. **Get Resource** — Fetch the current document by ID
2. **LLM Step** — Generate updated content based on the existing document
3. **Update Resource** — Patch only the fields that changed
### Content Migration
1. **List Resources** — Fetch documents from one dataset
2. **Loop** — Iterate over the list
3. **Create Resource** — Create each document in a different dataset
### Draft Review Pipeline
1. **Create Resource** — Create content as a draft (default behavior)
2. **Human Review** — Manual review step in Sanity Studio
3. **Publish Resource** — Publish approved drafts via the Agent
***
## Permissions and Roles
Profound validates that your API token has sufficient permissions on connection. The following Sanity roles are supported:
| Role | Can Create | Can Update | Can Publish | Can Read |
| ----------------- | ---------- | ---------- | ----------- | -------- |
| **Administrator** | Yes | Yes | Yes | Yes |
| **Editor** | Yes | Yes | Yes | Yes |
| **Developer** | Yes | Yes | Yes | Yes |
| **Viewer** | No | No | No | Yes |
**Minimum required role:** Editor. Tokens with Viewer-only access will fail when attempting to create, update, or publish documents.
***
## Troubleshooting
Your API token is invalid or has expired. Generate a new token in your [Sanity management console](https://www.sanity.io/manage) under **API → Tokens** and reconnect.
Your API token doesn't have Editor-level access. Create a new token with **Editor** permissions and reconnect.
The Project ID in your integration settings is incorrect. Verify the Project ID in your [Sanity management console](https://www.sanity.io/manage) — it's displayed at the top of your project page and in the URL.
When using **Create Resource**, your Data field must include a `_type` property that matches a document type defined in your Sanity schema. For example: `{ "_type": "post", "title": "Hello" }`.
The **Publish Resource** step requires a draft document ID that starts with `drafts.`. If the document is already published, it doesn't need to be published again. Check that you're passing the draft ID, not the published ID.
Make sure you're using the **Rich Text Content** field (not the **Document Details** field) for HTML-to-Portable-Text conversion. The Rich Text Content field expects a JSON object mapping field names to HTML strings: `{ "body": "Hello
" }`.
***
## Additional Resources
Learn more about Sanity's content model and API:
* [Sanity Content Lake](https://www.sanity.io/docs/content-lake) — Understanding datasets and documents
* [Portable Text](https://www.sanity.io/docs/block-content) — Sanity's rich text format specification
* [GROQ Query Language](https://www.sanity.io/docs/groq) — Querying content in Sanity
* [HTTP API Reference](https://www.sanity.io/docs/http-api) — Full Sanity API documentation
* [Mutations API](https://www.sanity.io/docs/http-mutations) — Creating, updating, and deleting documents
# Connect Wordpress to Profound
Source: https://docs.tryprofound.com/integrations/wordpress/connect-wordpress-to-profound
1. In Profound, go to **Account → Integrations → WordPress**.
2. Click **Connect account**.
3. Enter:
* **Username** (your WordPress login username)
* **Password** (the application password you generated)
* **Site URL** (for example, [https://example.com](https://example.com))
4. Click **Connect account** to finish.
Once connected, the WordPress site will appear as an available integration and can be selected inside Agents. Multiple WordPress sites can be connected to the same Profound organization.
# Create an Application Password in WordPress
Source: https://docs.tryprofound.com/integrations/wordpress/create-an-application-password-in-word-press
1. Log in to your WordPress admin panel.
2. Navigate to **Users → Profile** (or **Users → Edit** for the relevant admin user).
3. Scroll to **Application Passwords**.
4. Create a new application password (for example, “Profound Integration”).
5. Copy the generated password immediately. It will not be shown again.
**Important Notes**
* Use your actual WordPress **username**, not the application password label.
* Application Passwords require WordPress 5.6 or later.
* Treat the application password like a standard credential—it grants REST API access to your site.
# Using WordPress in Agents
Source: https://docs.tryprofound.com/integrations/wordpress/setup-and-authentication
After connecting a site, WordPress actions become available as Agent steps. Each step requires you to select a connected **WordPress Site** from a dropdown.
#### **Create Post**
Create a new post on a connected WordPress site.
**Required inputs**
* **WordPress Site**
* **Title**
* **Content**
**Optional inputs**
* **Status** (e.g., Draft or Publish)
* **Excerpt**
* **Slug**
This step is commonly used after content generation or transformation steps to draft or publish new articles.
#### **Update Post**
Update an existing post.
**Required inputs**
* **WordPress Site**
* **Post ID**
**Optional inputs**
* **Status**
* **Title**
* **Content**
* **Excerpt**
* **Slug**
This is useful for publishing drafts, revising existing content, or programmatically updating posts created earlier in the Agent.
\*\*Important Notes: \*\*Only the fields you provide will be modified; all other fields remain unchanged.
#### **List Posts**
Retrieve a list of posts from a connected WordPress site.
**Required inputs**
* **WordPress Site**
**Optional inputs**
* **Page** (pagination)
* **Per Page** (number of posts to return)
* **Post Status** (e.g., Publish)
The output is a structured list of posts that can be used in downstream Agent steps (for example, selecting a post to update).
#### **Get Post**
Retrieve a single post by ID.
**Required inputs**
* **WordPress Site**
* **Post ID**
The output includes the post’s data and can be referenced by later steps in the Agent.
# Tips & Troubleshooting
Source: https://docs.tryprofound.com/integrations/wordpress/tips-and-troublshooting
* If you do not see **Application Passwords** in WordPress, confirm your WordPress version and check whether a security plugin is disabling the feature.
* If you lose the application password, generate a new one in WordPress and reconnect the integration in Profound.
* Ensure the Site URL exactly matches how your WordPress site is accessed (including https and any subdirectory, if applicable).
# Introduction
Source: https://docs.tryprofound.com/introduction
Welcome to Profound developer documentation
See how AI sees your website with enterprise-grade analytics
### Integration guides
Profound seamlessly integrates with any website or application, providing powerful analytics and insights for your digital presence. Whether you're using a popular platform or have a custom setup, we have a solution for you.
Connect your Profound account to your Cloudflare account with a lightweight worker
Connect your Profound account to your Cloudflare account with Logpush
}
href="/agent-analytics/vercel_native"
>
Integrate your Vercel account with Agent Analytics in just a few clicks
Use Amazon Data Firehose to deliver real-time logs to Profound
Connect your Fastly traffic to Profound with a Custom HTTPS Endpoint
Connect your Netlify traffic to Profound with Log Drains
Connect your Akamai traffic to Profound with DataStream2
Connect your Google Cloud CDN traffic to Profound with a log sink
Use the WordPress plugin to send request logs to Profound
Select one of the Shopify integration options to send request logs to Profound
Forward AEM as a Cloud Service CDN logs to Profound via Log Forwarding
Build your own custom integration with standardized log drain formats
### Need Help?
Our team is here to support you every step of the way. For personalized assistance with your integration, reach out through your dedicated Slack channel.
Frequently Asked Questions about Agent Analytics and Google Analytics
Monitor our service health and stay updated on system performance in real-time
Work with our team to design and build integrations tailored to your unique infrastructure needs
# Authentication
Source: https://docs.tryprofound.com/mcp/authentication
Learn how to authenticate with the hosted Profound MCP server
## OAuth
Profound MCP uses OAuth 2.1. When your client prompts for authentication, complete the browser sign-in with your Profound account. Every tool call runs as the authenticated user and returns only the data that user can access.
OAuth is the recommended authentication method for all Profound MCP connections.
## Long-lived Bearer token (API key)
Profound MCP supports a long-lived Bearer token authentication based on an API key. This is useful for setups that can't complete a per-user OAuth flow each time, such as service accounts or internal tools.
### Requirements
* Profound [enterprise plan](https://www.tryprofound.com/enterprise)
* Access to Profound API: [contact our support team](mailto:support@tryprofound.com) to get it.
### Setup
Follow the instructions in [Getting Your API Key](/rest-api/authentication#getting-your-api-key) section of Profound API documentation.
In your MCP client's authentication settings for the Profound connection, select **Bearer Token** and enter:
```text theme={null}
Bearer
```
### Security notes
* Your API key is sensitive information. Treat it like a password: store it securely, never commit it to version control, and set an expiration date when you create it.
* Revoke keys you no longer use from the **API Keys** page in your Profound account settings.
# Agents capabilities
Source: https://docs.tryprofound.com/mcp/capabilities/agents-capabilities
Understand the Agent tools available through Profound MCP
Profound MCP gives AI assistants tools to build, manage, and run Profound Agents directly from an MCP client. Use them to create automated workflows that combine Profound data with LLM reasoning, code execution, and web search. To set up the server, refer to the [Connection guides](/mcp/common-mcp-clients).
```text Hosted server theme={null}
https://mcp.tryprofound.com/mcp
```
## How the tools work together
Agent workflows fall into two paths: running an existing Agent, or building and publishing a new one.
### Run an Agent
Use `list_agents` to browse Agents in the organization, or `list_agent_definition_templates` for pre-built Agent templates.
Use `get_agent` to read the Agent's `input_schema` before calling `run_agent`.
Use `run_agent` with inputs that match the Agent's `input_schema`.
Use `get_agent_run` with the `agent_id` and the `run_id` returned in the previous step, until the run reaches a terminal state.
### Build an Agent
Use `start_agent_build_session` with a short, plain-language `intent`. It returns an `agent_build_session_id`. Pass that same ID, unchanged, on every build call below so the whole attempt is traced as one session.
Use `list_agent_node_types` and `get_agent_node_schema` to assemble a workflow graph, or `list_agent_definition_templates` to start from a template.
Use `create_agent_definition` or `update_agent_definition` with `preview: true` to review the plan, then set `preview` to `false` to save the draft.
Use `validate_agent_definition` to catch structural issues early, and fix them with `update_agent_definition`. This is a fast pre-check, not the final word: publishing runs the authoritative validation.
Use `publish_agent_definition` with `preview: true` to review the plan, then set `preview` to `false` to make the Agent live.
#### Use natural language when working with Claude
If you're using Claude as the client, you can prompt it in natural language to build Agents in one go, without calling multiple tools.
Here's an example prompt and an Agent structure Claude may produce with it:
```text wrap theme={null}
Build an Agent in Profound that creates a structured, AEO-optimized article based on provided inputs. It should analyze top-cited pages, live Google results, and existing brand content to produce a well-researched article
```
## Behavior and safety
Agents tools can create and update Agent definitions and start Agent runs. Use `preview: true` (the default) on create, update, and publish tools to review changes before applying them.
| Behavior | What it means |
| -------------------- | ----------------------------------------------------------------------------------------- |
| Preview before apply | Create, update, and publish tools default to preview mode |
| Live data | Tools read from the Profound API, so results reflect the caller's current access and data |
## Agents tools
These tools let you build, manage, and run Agents directly from an MCP client.
| Tool | Use it for |
| --------------------------------- | --------------------------------------------------------------- |
| `list_agents` | List Agents available in an organization |
| `get_agent` | Get details of a specific Agent, including its input schema |
| `run_agent` | Start an Agent run |
| `get_agent_run` | Check the status and output of a previously started run |
| `start_agent_build_session` | Open a build session to build or revise an Agent |
| `list_agent_node_types` | List the node types available for building an Agent graph |
| `get_agent_node_schema` | Get the configuration schema for a specific node type |
| `list_agent_definition_templates` | Browse pre-built Agent templates to use as starting points |
| `get_agent_definition` | Read back an Agent's full workflow graph |
| `create_agent_definition` | Create a new draft Agent definition |
| `update_agent_definition` | Update an existing draft Agent definition |
| `validate_agent_definition` | Check whether a draft Agent definition is valid and publishable |
| `publish_agent_definition` | Publish a draft Agent definition so it goes live |
List Agents defined in the authenticated organization.
| Input | Required | Default | Description |
| ---------- | -------- | --------------- | ---------------------------------------------------------------- |
| `statuses` | No | `["published"]` | Lifecycle states to include, e.g. `["published"]` or `["draft"]` |
| `cursor` | No | - | Pagination cursor from a previous page |
| `limit` | No | - | Maximum number of Agents to return |
Get details of a specific Agent, including its `input_schema`. Use this before calling `run_agent` to confirm which inputs the Agent expects.
| Input | Required | Default | Description |
| ---------- | -------- | ----------- | ---------------------------------------------------------------------------- |
| `agent_id` | Yes | - | ID of the Agent to retrieve |
| `version` | No | `published` | `published` for the live version, `draft` for the latest unpublished changes |
Start an Agent run. Returns a run ID you can poll with `get_agent_run`.
| Input | Required | Default | Description |
| ---------- | -------- | ------- | --------------------------------------------------------------------------------------------------------------------- |
| `agent_id` | Yes | - | ID of the Agent to run |
| `inputs` | Yes | - | Input values keyed by the property IDs in the Agent's `input_schema` (the opaque keys, not the human-readable labels) |
Each key in `inputs` is a property ID from `input_schema.properties`. The readable label lives in that property's `title`. Fetch the schema with `get_agent` first.
Example:
```json theme={null}
{
"agent_id": "agent_123",
"inputs": { "b1f2c3d4-...": "AI search trends" }
}
```
Get the status and outputs of a previously started Agent run. Poll this until the run reaches a terminal state.
| Input | Required | Default | Description |
| ---------- | -------- | ------- | ---------------------------------- |
| `agent_id` | Yes | - | ID of the Agent the run belongs to |
| `run_id` | Yes | - | Run ID returned by `run_agent` |
Open an Agent build session, the first step before building or revising an Agent. Call it before any other build tool, then pass the returned `agent_build_session_id`, unchanged, on every subsequent build call so the whole attempt is traced as one session. It persists nothing and does not create an Agent.
| Input | Required | Default | Description |
| -------- | -------- | ------- | ------------------------------------------------------------- |
| `intent` | Yes | - | Short, plain-language description of what the Agent should do |
List the node types available for building an Agent graph. Returns each type's `node_type` identifier, display name, and a one-line description. Call this after opening a build session, when assembling a new Agent.
**Inputs:** none.
Get the configuration schema and examples for a specific node type. Use the returned schema to fill a node's `config` correctly when building or editing an Agent graph.
| Input | Required | Default | Description |
| ----------- | -------- | ------- | ------------------------------------------------- |
| `node_type` | Yes | - | Node type identifier from `list_agent_node_types` |
Example:
```json theme={null}
{
"node_type": "llm"
}
```
Browse pre-built Agent templates. Each template includes a plain-language goal, the inputs it needs, what it produces, and a skeleton workflow you can use as a starting point. Call this before building a new Agent from scratch.
**Inputs:** none.
Read back an Agent's full workflow graph in the same format that `create_agent_definition` and `update_agent_definition` accept. Useful for copying an existing Agent or inspecting a node type you want to replicate.
| Input | Required | Default | Description |
| ---------- | -------- | ----------- | ---------------------------------------------------------------------------- |
| `agent_id` | Yes | - | ID of the Agent to read |
| `version` | No | `published` | `published` for the live version, `draft` for the latest unpublished changes |
Create a new draft Agent definition. Set `preview` to `true` (the default) to see a plain-language plan and workflow diagram without persisting anything. Set `preview` to `false` to save the draft after the user confirms.
| Input | Required | Default | Description |
| ------------------------ | -------- | ------- | --------------------------------------------------------------------- |
| `name` | Yes | - | Display name for the Agent |
| `description` | Yes | - | What the Agent does |
| `organization_id` | Yes | - | Organization to create the Agent in, from `list_organizations` |
| `graph` | Yes | - | The workflow graph as a `{ nodes, edges }` object |
| `agent_build_session_id` | Yes | - | Session ID from `start_agent_build_session` |
| `preview` | No | `true` | Return a plan without saving when `true`; save the draft when `false` |
Update an existing draft Agent definition. Use this to fix validation issues after `create_agent_definition` or to iterate on a saved draft. Supports the same `preview` / apply loop as `create_agent_definition`.
| Input | Required | Default | Description |
| ------------------------ | -------- | ------- | ----------------------------------------------------------- |
| `agent_id` | Yes | - | ID of the draft Agent to update |
| `graph` | Yes | - | The updated workflow graph |
| `agent_build_session_id` | Yes | - | Session ID from `start_agent_build_session` |
| `preview` | No | `true` | Return a plan without saving when `true`; save when `false` |
Check whether a saved draft Agent definition is well-formed. Returns `valid` (boolean), `issues` (list of actionable errors), and, when the draft is publishable, the `input_schema` and `output_schema` the Agent will expose once live. This is a fast structural pre-check: publishing runs the authoritative validation, so a draft can pass here and still be rejected at publish. Fix any issues with `update_agent_definition`.
| Input | Required | Default | Description |
| ------------------------ | -------- | ------- | ------------------------------------------- |
| `agent_id` | Yes | - | ID of the draft Agent to validate |
| `agent_build_session_id` | Yes | - | Session ID from `start_agent_build_session` |
Publish a draft Agent definition so it goes live and is visible across the organization. Supports a `preview` step that returns a plan before applying. Call `validate_agent_definition` first to confirm the draft is valid.
| Input | Required | Default | Description |
| ------------------------ | -------- | ------- | ------------------------------------------------------------------ |
| `agent_id` | Yes | - | ID of the draft Agent to publish |
| `agent_build_session_id` | Yes | - | Session ID from `start_agent_build_session` |
| `preview` | No | `true` | Return a plan without publishing when `true`; publish when `false` |
# Analytics capabilities
Source: https://docs.tryprofound.com/mcp/capabilities/analytics-capabilities
Understand the analytics tools and resources available through Profound MCP
Profound MCP gives AI assistants read-only access to Profound's Answer Engine Optimization (AEO), brand visibility, citation, sentiment, and agent analytics data. Use this page to understand what the hosted MCP server can do before connecting it to an MCP client. To set up the server, refer to the [Connection guides](/mcp/common-mcp-clients).
```text Hosted server theme={null}
https://mcp.tryprofound.com/mcp
```
## How the tools work together
Most workflows start with discovery, then move into reports. Here's what that typically looks like:
Use `whoami` to confirm the signed-in user, available organizations, regions, and entitlements.
Use `list_organizations`, then `list_categories` for visibility reports or `list_domains` for traffic reports.
Use `list_regions`, `list_models`, `list_tags`, `list_topics`, and `list_prompts` to narrow a report to the relevant market, AI engine, prompt set, topic, or tag.
Use the visibility, sentiment, citations, prompt answers, referrals, or bot crawl tools to retrieve analytics for a date range.
## Behavior and safety
All tools are read-only. They retrieve analytics and reference data, but don't create, update, or delete anything in Profound.
| Behavior | What it means |
| --------------- | ----------------------------------------------------------------------------------------- |
| Non-destructive | No tool performs destructive updates |
| Live data | Tools read from the Profound API, so results reflect the caller's current access and data |
The following MCP hints are set on all report tools:
| Hint | Value | What it means |
| ---------------- | ------ | ------------------------------------------------- |
| `readOnlyHint` | `true` | The tool only reads data |
| `idempotentHint` | `true` | The tool is safe to retry with the same arguments |
Dates are ISO 8601 strings in `YYYY-MM-DD` format. Reports validate `start_date` and `end_date` and return an actionable error if the date window is invalid.
## Discovery tools
Use discovery tools to resolve human-readable context into IDs that report tools can use.
| Tool | Use it for |
| -------------------- | ----------------------------------------------------------------------------------- |
| `whoami` | Confirm the authenticated principal, organizations, regions, and entitlements |
| `list_organizations` | List organizations the user can access |
| `list_regions` | List geographic regions, optionally scoped to an organization |
| `list_models` | List tracked AI models such as ChatGPT, Perplexity, Google AI Overviews, and Gemini |
| `list_categories` | List tracked categories for an organization |
| `list_domains` | List tracked domains for an organization |
| `list_tags` | List tags in a category |
| `list_topics` | List topics in a category |
| `list_prompts` | List configured prompts in a category, with optional status, tag, and topic filters |
Confirm the authenticated user, organizations, regions, and entitlements available to this MCP session.
**Inputs:** none.
List the organizations the authenticated user can access. Returned IDs feed category, domain, and report tools.
**Inputs:** none.
List geographic regions configured for an organization. Omit `org_id` to see regions across all accessible organizations.
| Input | Required | Default | Description |
| -------- | -------- | ------- | ------------------------ |
| `org_id` | No | `null` | Organization to scope to |
Example:
```json theme={null}
{
"org_id": "org_123"
}
```
List the AI models Profound tracks. Use returned model IDs to filter reports to a single engine.
**Inputs:** none.
List tracked categories, markets, or segments in an organization. Most brand visibility reports are scoped to a category.
| Input | Required | Default | Description |
| -------- | -------- | ------- | ------------------------------------- |
| `org_id` | Yes | - | Organization whose categories to list |
Example:
```json theme={null}
{
"org_id": "org_123"
}
```
List tracked domains for an organization. Domains are exact hostnames, so `www.example.com` and `example.com` are distinct.
| Input | Required | Default | Description |
| -------- | -------- | ------- | ------------------------------------------ |
| `org_id` | Yes | - | Organization whose tracked domains to list |
Example:
```json theme={null}
{
"org_id": "org_123"
}
```
List tags available within a category for filtering prompts and reports.
| Input | Required | Default | Description |
| ------------- | -------- | ------- | --------------------------- |
| `category_id` | Yes | - | Category whose tags to list |
Example:
```json theme={null}
{
"category_id": "cat_123"
}
```
List topics available within a category for filtering prompts and reports.
| Input | Required | Default | Description |
| ------------- | -------- | ------- | --------------------------- |
| `category_id` | Yes | - | Category to list topics for |
Example:
```json theme={null}
{
"category_id": "cat_123"
}
```
List prompts configured in a category. Prompts are the questions Profound runs against AI engines to measure brand visibility.
| Input | Required | Default | Description |
| ------------------- | -------- | ------- | --------------------------------------------------------- |
| `category_id` | Yes | - | Category to list prompts for |
| `status` | No | `all` | One of `active`, `disabled`, or `all` |
| `tag_ids` | No | `null` | Include only prompts carrying these tags |
| `topic_ids` | No | `null` | Include only prompts under these topics |
| `exclude_tag_ids` | No | `null` | Exclude prompts carrying these tags |
| `exclude_topic_ids` | No | `null` | Exclude prompts under these topics |
| `combine` | No | `AND` | How include filters combine: `AND` or `OR` |
| `limit` | No | `100` | Maximum prompts to return |
| `cursor` | No | `null` | Pagination token from a previous response's `next_cursor` |
Example:
```json theme={null}
{
"category_id": "cat_123",
"status": "active"
}
```
## Brand visibility reports
These tools are scoped to a `category_id` and a date range. Use them to understand how brands appear in AI answers, how those answers feel, and which sources AI engines cite.
| Tool | Description |
| ----------------------- | --------------------------------------------------------------------------------------------------------- |
| `get_visibility_report` | How visible a brand is in AI answers and how that varies by model, topic, region, prompt, tag, or persona |
| `get_sentiment_report` | What sentiment AI answers express about a brand or competitor and which themes are positive or negative |
| `get_citations_report` | Which domains, pages, or URLs are AI engines citing for this category |
| `get_prompt_answers` | What raw AI answers were observed behind the metrics |
| `get_factcheck_report` | FactCheck scores for a category over a date range |
| `get_factcheck_claims` | Inaccurate claims identified in a category over a date range |
Measure how often and how prominently a brand appears in AI answers for a category over a date range.
Default metric: `visibility_score`.
Other useful metrics include `share_of_voice`, `mentions_count`, `executions`, and `average_position`. Useful dimensions include `date`, `region`, `topic`, `model`, `prompt`, `tag`, and `persona`.
| Input | Required | Default | Description |
| ---------------- | -------- | ------------------ | ------------------------------------------------------- |
| `category_id` | Yes | - | Category to report on |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `metrics` | No | `visibility_score` | Metrics to return |
| `dimensions` | No | `null` | Group-by fields |
| `filters` | No | `null` | Advanced `{ "field", "operator", "value" }` predicates |
| `limit` | No | `null` | Top-N row cap. When set, `next_cursor` is always `null` |
| `topic_filter` | No | `null` | Narrow to one or more topics |
| `tag_filter` | No | `null` | Narrow to one or more tags |
| `region_filter` | No | `null` | Narrow to one or more regions |
| `model_filter` | No | `null` | Narrow to one or more AI models |
| `persona_filter` | No | `null` | Narrow to one or more personas |
| `asset_filter` | No | `null` | Narrow to one or more brand or competitor assets |
| `cursor` | No | `null` | Pagination token from a previous response |
| `page_size` | No | `500` | First-page size, up to 10,000 |
Example:
```json theme={null}
{
"category_id": "cat_123",
"start_date": "2026-04-01",
"end_date": "2026-05-01",
"dimensions": ["model"]
}
```
Measure sentiment in AI answers for a category over a date range.
Default metrics: `positive`, `negative`, and `occurrences`. `positive` and `negative` are weighted aggregates; `occurrences` is a raw count.
| Input | Required | Default | Description |
| ---------------- | -------- | ------------------------------------- | ------------------------------------------------------- |
| `category_id` | Yes | - | Category to report on |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `metrics` | No | `positive`, `negative`, `occurrences` | Metrics to return |
| `filters` | No | `null` | Advanced `{ "field", "operator", "value" }` predicates |
| `limit` | No | `null` | Top-N row cap. When set, `next_cursor` is always `null` |
| `topic_filter` | No | `null` | Narrow to one or more topics |
| `tag_filter` | No | `null` | Narrow to one or more tags |
| `region_filter` | No | `null` | Narrow to one or more regions |
| `model_filter` | No | `null` | Narrow to one or more AI models |
| `persona_filter` | No | `null` | Narrow to one or more personas |
| `asset_filter` | No | `null` | Narrow to one or more brand or competitor assets |
| `theme_filter` | No | `null` | Narrow to one or more sentiment themes, such as pricing |
| `cursor` | No | `null` | Pagination token from a previous response |
| `page_size` | No | `500` | First-page size, up to 10,000 |
Example:
```json theme={null}
{
"category_id": "cat_123",
"start_date": "2026-04-01",
"end_date": "2026-05-01",
"theme_filter": "pricing"
}
```
See which sources AI engines cite for a category, and how often, over a date range.
Default metrics: `count` and `citation_share`. Useful dimensions include `hostname`, `path`, `root_domain`, `url`, `model`, `topic`, `prompt`, `tag`, and `persona`.
`root_domain_filter` must be paired with `dimensions: ["root_domain"]`.
| Input | Required | Default | Description |
| -------------------------- | -------- | ------------------------- | -------------------------------------------------------------------------- |
| `category_id` | Yes | - | Category to report on |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `metrics` | No | `count`, `citation_share` | Metrics to return |
| `dimensions` | No | `null` | Group-by fields |
| `filters` | No | `null` | Advanced `{ "field", "operator", "value" }` predicates |
| `limit` | No | `null` | Top-N row cap. When set, `next_cursor` is always `null` |
| `topic_filter` | No | `null` | Narrow to one or more topics |
| `tag_filter` | No | `null` | Narrow to one or more tags |
| `region_filter` | No | `null` | Narrow to one or more regions |
| `model_filter` | No | `null` | Narrow to one or more AI models |
| `persona_filter` | No | `null` | Narrow to one or more personas |
| `root_domain_filter` | No | `null` | Narrow to one or more root domains. Requires `root_domain` in `dimensions` |
| `hostname_filter` | No | `null` | Narrow to one or more hostnames |
| `citation_category_filter` | No | `null` | Narrow to one or more citation categories |
| `cursor` | No | `null` | Pagination token from a previous response |
| `page_size` | No | `500` | First-page size, up to 10,000 |
Example:
```json theme={null}
{
"category_id": "cat_123",
"start_date": "2026-04-01",
"end_date": "2026-05-01",
"dimensions": ["root_domain"]
}
```
Retrieve the actual answers AI engines gave for a category's prompts over a date range.
| Input | Required | Default | Description |
| ------------- | -------- | ------- | ----------------------------------------------- |
| `category_id` | Yes | - | Category to retrieve prompt answers for |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `limit` | No | `100` | Rows per page |
| `offset` | No | `0` | Row offset for pagination |
Example:
```json theme={null}
{
"category_id": "cat_123",
"start_date": "2026-04-01",
"end_date": "2026-05-01"
}
```
## Traffic reports
These tools are scoped to a tracked domain, not a category. Use `list_domains` first and pass the exact hostname returned by Profound.
| Tool | Description |
| ---------------------- | ------------------------------------------------------------------------------------ |
| `get_referrals_report` | How many visits did a domain receive from AI engines, and which referrers drove them |
| `get_bots_report` | Which AI crawlers are visiting a domain, and how often |
Measure visits a domain received from AI engines, such as ChatGPT and Perplexity, over a date range.
Default metric: `visits`. Useful dimensions include `referral_type`, `referral_source`, and `date`.
| Input | Required | Default | Description |
| ------------------------ | -------- | -------- | ---------------------------------------------------------------------------------- |
| `domain` | Yes | - | Tracked domain, using the exact hostname from `list_domains` |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `metrics` | No | `visits` | Metrics to return |
| `dimensions` | No | `null` | Group-by fields, such as `referral_type`, `referral_source`, or `date` |
| `organization_id` | No | `null` | Disambiguates the domain when the caller belongs to multiple organizations |
| `filters` | No | `null` | Advanced `{ "field", "operator", "value" }` predicates |
| `limit` | No | `null` | Top-N row cap. When set, makes `next_cursor` always `null` |
| `referral_source_filter` | No | `null` | Narrow to one or more referrer vendors, such as `openai` |
| `referral_type_filter` | No | `null` | Narrow to one or more referral categories: `internal`, `referer`, `utm`, or `none` |
| `cursor` | No | `null` | Pagination token from a previous response |
| `page_size` | No | `500` | First-page size, up to 10,000 |
Example:
```json theme={null}
{
"domain": "example.com",
"start_date": "2026-04-01",
"end_date": "2026-05-01",
"dimensions": ["referral_source"]
}
```
Measure AI crawler activity against a domain over a date range, including bots such as GPTBot and PerplexityBot.
Default metrics: `count` and `citations`. Useful dimensions include `bot_provider`, `bot_name`, `bot_type`, and `date`.
| Input | Required | Default | Description |
| --------------------- | -------- | -------------------- | ------------------------------------------------------------------------------------------- |
| `domain` | Yes | - | Tracked domain, using the exact hostname from `list_domains` |
| `start_date` | Yes | - | Window start (inclusive) in `YYYY-MM-DD` format |
| `end_date` | Yes | - | Window end (inclusive) in `YYYY-MM-DD` format |
| `metrics` | No | `count`, `citations` | Metrics to return |
| `dimensions` | No | `null` | Group-by fields, such as `bot_provider`, `bot_name`, `bot_type`, or `date` |
| `organization_id` | No | `null` | Disambiguates the domain when the caller belongs to multiple organizations |
| `filters` | No | `null` | Advanced `{ "field", "operator", "value" }` predicates |
| `limit` | No | `null` | Top-N row cap. When set, makes `next_cursor` always `null` |
| `bot_provider_filter` | No | `null` | Narrow to one or more providers, such as `openai` or `anthropic` |
| `bot_name_filter` | No | `null` | Narrow to one or more individual bots, such as `GPTBot` |
| `bot_type_filter` | No | `null` | Narrow to one or more bot categories: `ai_assistant`, `ai_training`, `index`, or `ai_agent` |
| `cursor` | No | `null` | Pagination token from a previous response |
| `page_size` | No | `500` | First-page size, up to 10,000 |
Example:
```json theme={null}
{
"domain": "example.com",
"start_date": "2026-04-01",
"end_date": "2026-05-01",
"dimensions": ["bot_provider"]
}
```
## Resources
Profound MCP also exposes read-only MCP resources: static reference material that an MCP client can load into context.
| Resource URI | Audience | Use it for |
| ---------------------------------- | --------- | ------------------------------------------------------------------ |
| `file:///profound/glossary` | Assistant | Compact index of Profound-specific terms to load once per session |
| `file:///profound/glossary/full` | User | Full glossary with definitions and examples, larger than the index |
| `file:///profound/glossary/{term}` | Assistant | Full definition of one glossary term, addressed by slug |
The glossary defines recurring Profound terms such as visibility score, share of voice, citations, prompts, and AI engines.
A client typically loads `file:///profound/glossary` once, then fetches a specific term with `file:///profound/glossary/{term}` when it needs a precise definition. For example, use `file:///profound/glossary/visibility-score` for the visibility score definition.
The glossary includes 38 terms across seven categories: Identity, Taxonomy, AI Engines, Prompts, Reports, Metrics, and Agents.
Each term has a stable lowercase hyphenated slug, short summary, full description, examples, and see-also references to related terms.
# Connection guides
Source: https://docs.tryprofound.com/mcp/common-mcp-clients
Connect your AI tool to Profound MCP
If your tool is not listed here, check its MCP documentation for support for remote hosted MCP servers. See the [AI tools connection guide](/mcp/connection-tutorials/connect-ai-coding-tools) for the server URL and JSON configuration.
# Connect AI coding tools to Profound MCP
Source: https://docs.tryprofound.com/mcp/connection-tutorials/connect-ai-coding-tools
This guide walks you through connecting your AI tool to Profound using our hosted MCP server.
```text Streamable HTTP theme={null}
https://mcp.tryprofound.com/mcp
```
## Claude Code
Run this command in your terminal:
```bash theme={null}
claude mcp add --transport http profound https://mcp.tryprofound.com/mcp
```
Use `/mcp` in Claude Code to confirm the server is installed and complete any authentication flow if prompted.
* `--scope local` installs the server only for the current project
* `--scope project` shares the configuration with your team in the project
* `--scope user` installs the server across your projects
For more details, see [Claude Code MCP Installation Scopes](https://code.claude.com/docs/en/mcp#mcp-installation-scopes).
## Claude Desktop
Open **Settings** -> **Connectors** in Claude Desktop.
Search for **Profound** on the connectors list, select **Connect**.
Complete any authentication flow if prompted.
## Cursor
Open **Cursor Settings** -> **Tools & MCPs** -> **New MCP Server**.
Add the following configuration:
```json theme={null}
{
"mcpServers": {
"profound": {
"url": "https://mcp.tryprofound.com/mcp"
}
}
}
```
Save changes to the config.
Open **Cursor Settings** -> **Tools & MCPs** -> **New MCP Server**.
Look for the `profound` MCP server entry, click the **Connect** button, and complete any authentication flow if prompted.
## OpenCode
Add Profound MCP to your OpenCode config:
```json theme={null}
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"profound": {
"type": "remote",
"url": "https://mcp.tryprofound.com/mcp",
"enabled": true
}
}
}
```
If OpenCode prompts for authentication, run `opencode mcp auth profound`.
## VS Code
Create a `.vscode/mcp.json` file in your workspace:
```json theme={null}
{
"servers": {
"profound": {
"type": "http",
"url": "https://mcp.tryprofound.com/mcp"
}
}
}
```
Open the Command Palette and run **MCP: List Servers**.
Start the Profound server and complete any authentication flow if prompted.
## Windsurf
Open **Windsurf Settings** and search for **MCP**.
Open the raw `mcp_config.json` file and add the following configuration:
```json theme={null}
{
"mcpServers": {
"profound": {
"serverUrl": "https://mcp.tryprofound.com/mcp"
}
}
}
```
Save the configuration and restart Windsurf.
## Other Tools
### JSON Configuration Format
Most MCP clients accept a JSON configuration.
```json Streamable HTTP theme={null}
{
"mcpServers": {
"profound": {
"url": "https://mcp.tryprofound.com/mcp"
}
}
}
```
## Troubleshooting
### Authentication Issues
If your client prompts for authentication and the connection fails, try restarting the client and reconnecting. If your client offers a disconnect option for MCP servers, disconnect the existing connection and try again.
If you need a long-lived credential instead of the OAuth flow, see [Authentication](/mcp/authentication) for the Bearer token (API key) alternative.
# Connect ChatGPT to Profound MCP
Source: https://docs.tryprofound.com/mcp/connection-tutorials/connect-chatgpt
This guide walks you through connecting Profound to ChatGPT using the Profound MCP server. Once connected, ChatGPT can access Profound data and capabilities directly in conversation.
## Before you start
You'll need:
* A [ChatGPT](https://chatgpt.com/) account on a plan that supports developer mode. Learn more in the [OpenAI developer mode documentation](https://developers.openai.com/api/docs/guides/developer-mode)
* A [Profound](https://www.tryprofound.com/) account
## Setup guide
In [ChatGPT](https://chatgpt.com/), open your account menu in the lower-left corner of the screen, and select **Settings**.
Under **Security and login**, enable **Developer mode**.
Go to the ChatGPT [Plugins page](https://chatgpt.com/plugins) and select **+**.
In the New Plugin dialog, fill in the fields as follows:
* **Name:** profound
* **Description:** Provides AEO and GEO marketing analytics and allows agents to operate the Profound platform.
* **MCP server URL:** `https://mcp.tryprofound.com/mcp`
* **Authentication:** OAuth
Under the custom MCP servers risk notice, select **I understand and want to continue**, then select **Create**.
Profound uses OAuth 2.0. Complete the flow with your Profound account.
If you have access to multiple Profound organizations, select the one you want to use with the Profound MCP server.
After you configure the Profound plugin, it appears among the available plugins in **Plugins** > **Personal** in ChatGPT.
Select the plugin, then select **Install** on the plugin page.
* Open **Settings** > **Plugins**.
* Confirm that **profound** appears in your list of installed plugins.
## Troubleshooting
If the plugin fails to create or ChatGPT can't reach Profound:
* Remove the plugin and add it again as instructed in [Step 2](#step2).
* If authentication fails, sign out of Profound in your browser, sign back in, and retry.
# Connect Gemini CLI to Profound MCP
Source: https://docs.tryprofound.com/mcp/connection-tutorials/connect-gemini-cli
This guide shows you how to connect Gemini CLI to the Profound MCP server, so Gemini can pull your Profound visibility data and run Profound actions directly from the terminal.
## Before you start
Make sure you have:
* [Gemini CLI](https://geminicli.com/) installed
* A [Profound](https://www.tryprofound.com/) account
## Setup guide
1. Run Gemini CLI in your terminal:
```bash theme={null}
gemini
```
2. When asked **How would you like to authenticate for this project?**, select **Sign in with Google**. Gemini will launch a browser session.
3. In the browser, select your Google account and sign in.
If successful, you'll see tips to get started and the command line.
1. MCP servers are configured in the `~/.gemini/settings.json` configuration file. To add the Profound server, create the `mcpServers` block with the Profound server details in `settings.json`:
```json theme={null}
"mcpServers": {
"profound": {
"url": "https://mcp.tryprofound.com/mcp"
}
}
```
You can do this in your preferred code editor, or directly from Gemini CLI by entering the prompt:
```text theme={null}
Add an MCP server called profound with url https://mcp.tryprofound.com/mcp
```
2. Review the changes and apply them if the `mcpServers` block looks correct.
3. For the changes to take effect, quit and reopen your Gemini CLI.
4. To verify the server was added, run the command to list the MCP servers inside the CLI.
```bash theme={null}
/mcp list
```
It should show `profound` among the configured MCP servers.
Profound authenticates with OAuth. Gemini CLI discovers the OAuth endpoints automatically, so no API keys, client ID, or secret are needed.
1. Inside the CLI, run the command to authenticate with Profound:
```bash theme={null}
/mcp auth profound
```
2. Select **Yes** when asked to authenticate in the browser. This will open the browser to the Profound sign-in page.
3. If you're not logged in, follow the prompts to log in to your Profound account. Then approve access.
When you see the success message, return to the Gemini CLI session in your terminal.
Still inside Gemini CLI, run the MCP list command again.
```bash theme={null}
/mcp list
```
If the Profound server shows as **Ready** with a green circle and has available tools listed, it's connected and ready to go.
For more details about configuring MCP server connections in Gemini CLI, see Gemini CLI's [MCP server documentation](https://geminicli.com/docs/tools/mcp-server).
## Troubleshooting
### The browser doesn't open during sign-in
Make sure you have a local browser installed. OAuth won't work in headless or remote sessions without browser access. Run the setup where you can open a browser, then retry signing in or authenticating with Profound.
### Profound server shows as disconnected
Re-run `/mcp auth profound` to refresh the token. If it still fails, sign out of Profound in your browser, sign back in, and retry.
# Connect Microsoft Copilot Studio agent to Profound MCP
Source: https://docs.tryprofound.com/mcp/connection-tutorials/connect-ms-copilot
This guide walks you through connecting Profound to a Microsoft Copilot Studio agent using the Profound MCP server. Once connected, your agent can access Profound data and capabilities directly.
## Before you start
Before you get started, you'll need:
* [Access to a Microsoft Copilot Studio account](https://learn.microsoft.com/en-us/microsoft-copilot-studio/requirements-licensing-subscriptions) with an [agent set up](https://learn.microsoft.com/en-us/microsoft-copilot-studio/fundamentals-get-started)
* A [Profound](https://www.tryprofound.com/) account
## Setup guide
* Sign in to [Microsoft Copilot Studio](https://copilotstudio.microsoft.com/)
* Go to the **Agents** tab in the left navigation bar
* Select and open the agent you want to connect Profound to
* Go to the **Tools** tab for the agent
* Select **+ New tool**
* In the New tool dialog window, select **Model Context Protocol**
After the setup wizard appears, fill in the fields as follows:
* **Server name:** Profound
* **Server description:** Provides AEO and GEO marketing analytics as well as allows agents to operate the Profound platform.
* **Server URL:** `https://mcp.tryprofound.com/mcp`
* **Authentication:** OAuth 2.0
Profound uses OAuth 2.0 to verify your identity. This is the standard "sign in with your account" method used by most modern apps.
After you select OAuth 2.0 as the authentication method in the setup wizard form:
* Select **Dynamic discovery**: This is the simplest option that lets Copilot Studio configure the sign-in flow automatically
* Select **Create**
After that, the **Add tool** dialog appears.
* On the Add tool screen, select **Create a new connection**
* Follow any sign-in prompts to authenticate with your Profound account
* After the connection is created, select **Save** for the MCP server, then refresh the tools list
* Select **Add to agent** to finish
Your agent now has access to the Profound MCP server.
To confirm everything is working:
* Go to the **Tools** tab for your agent
* Look for **Profound** in the list of connected tools
If it shows as connected, you're ready to go.
If the connection doesn't appear or the agent can't reach Profound, try removing the tool and adding it again from step 2. If authentication fails during setup, sign out of Profound in your browser, sign back in, and retry.
For more details about configuring MCP servers in Copilot Studio, see Microsoft's [Add an existing MCP server to an agent](https://learn.microsoft.com/en-us/microsoft-copilot-studio/mcp-add-existing-server-to-agent) guide.
# Connect WRITER AI Studio to Profound MCP
Source: https://docs.tryprofound.com/mcp/connection-tutorials/connect-writer
Connect Profound MCP to WRITER's AI Studio so your WRITER agents can pull live data directly from Profound.
## Before you start
You'll need:
* Access to [WRITER AI Studio](http://app.writer.com/aistudio)
* A [Profound](https://www.tryprofound.com/) account
## Setup guide
In WRITER AI Studio, go to **Connectors & Tools > Connectors** in the left sidebar and select **+ Custom connector**.
When prompted to choose a connector type, select **Connect to an MCP server** and enter the Profound server URL: `https://mcp.tryprofound.com/mcp`.
In the **Edit connector details** screen, fill in the fields as follows:
* **Connector name:** Profound
* **About this connector:** Provides AEO and GEO marketing analytics as well as allows agents to operate the Profound platform
Select **Next**.
On the **Connect to Profound** screen, scroll to **Define Authentication** and fill in the fields:
* **Authentication type:** OAuth
* **Authorization URL:** `https://auth.tryprofound.com/oauth2/authorize`
* **Access token URL:** `https://auth.tryprofound.com/oauth2/token`
* **DCR:** Yes
Leave the rest of the fields empty or at their default values, and select **Next** to complete the connection.
To confirm everything is working:
1. Go to **Connectors & Tools > Connectors** in the left sidebar in the AI Studio UI.
2. Select **+ New connector**.
3. Look for the Profound connector in the list.
Your Profound MCP connector is now available to use.
For more details about configuring custom MCP connectors in AI Studio, see WRITER's [Custom connectors guide](https://dev.writer.com/home/custom-connectors).
## Troubleshooting
### Rate limit exceeded
If you see a `rate limit reached` error, it's coming from WRITER. Wait a few minutes and try creating a connector again.
### Connection failed
If the connection fails after the rate limit error, the connector may have still been created. Check your available connectors and if it's not there, try creating a connector again.
# Overview
Source: https://docs.tryprofound.com/mcp/overview
Learn how to connect AI agents to Profound
Connect AI tools and agents to Profound using the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/introduction) open source standard for connecting AI applications to external systems.
## What is Profound MCP?
Profound MCP is our hosted server for integrating with AI tools that support MCP. Instead of wiring up a custom integration from scratch, you connect an MCP client to Profound and let the client call tools to execute API operations with your Profound account.
### Why use Profound MCP?
Profound MCP lets you connect to Profound quickly, without building a custom integration. Your Profound data and Agents become available directly inside the AI tool you already use. See how to connect common MCP clients to Profound in [Connection guides](/mcp/common-mcp-clients).
### What can you do with Profound MCP?
* **Docs** — Search Profound docs, endpoint, and authentication patterns before you start building
* **Visibility Reports** — Retrieve visibility metrics and performance data for companies within specific categories
* **Sentiment Analysis** — Analyze sentiment data and emotional responses across companies and topics
* **Citation Reports** — Track mentions, references, and citation patterns across domains and pages
* **Raw Data Access** — Access unprocessed data for custom analysis and reporting
* **Agent Analytics** — Access bot reports, referral reports, and raw analytics data
* **Build and Run Profound Agents** — Start existing Agents, create and publish new workflows, and poll runs for status and outputs
For the full tool and resource catalog, see [Analytics capabilities](/mcp/capabilities/analytics-capabilities) and [Agents capabilities](/mcp/capabilities/agents-capabilities).
# Configure SSO
Source: https://docs.tryprofound.com/platform-config/authentication/configure-sso
Set up Single Sign-On with Profound over SAML or OIDC
This guide explains how to set up Single Sign-On (SSO) with Profound over Security Assertion Markup Language (SAML) or OpenID Connect (OIDC). Profound supports various identity providers (IdPs), including Microsoft Azure AD, Google Workspace, Okta, and any custom SAML-compliant or OIDC-compliant IdP.
SSO is available for customers on the Enterprise plan. Setup requires the Admin role in your Profound organization. Learn more in [Roles and permissions](/platform-config/people/roles-and-permissions).
## Before you start
You'll need:
* The Admin role in your Profound organization
* Administrative access to your IdP
* The domain you want to enable for SSO
* Access to your DNS records to verify domain ownership
## Setup steps
Go to **Settings** in the settings icon menu at the bottom left of the platform.
Then select **Enterprise Setup** under **Organization** in the left navigation sidebar. The **Single Sign-On** card shows your current SSO status and verified domains. Select **Configure SSO** (or **Manage SSO**, if SSO is already set up) to open the configuration portal.
Follow the domain verification step in the portal and add the record it provides to your DNS. Verification confirms your organization owns the domain and unlocks the rest of the configuration.
Select your IdP from the list of supported options. The portal tailors the setup experience to your IdP: once you make your selection, it shows step-by-step instructions specific to your provider.
If your provider is not on the list, custom SAML or OIDC connection options are available.
The portal walks you through connecting your IdP to Profound. It shows the values to copy from Profound into your IdP, and the values to retrieve from your IdP and enter into the portal.
The values you exchange depend on your SSO protocol:
* Profound → IdP: the Authorized Redirect URI
* IdP → Profound: the Discovery Endpoint, Client ID, and Client Secret
* Profound → IdP: the ACS URL, Service Provider Entity ID, and Metadata URL
* IdP → Profound: the SSO URL, Entity ID, and X.509 Certificate
Follow the instructions shown in the portal for your specific IdP and protocol.
The configuration portal includes a built-in test feature. Use it to verify the connection and the login flow before going live.
Once the test passes, enable SSO for your domain directly from the portal. Back on the **Enterprise Setup** page, the status reads **SSO Enabled** and your domain is marked **Verified**. Select **Check status** to refresh.
After you enable SSO, users with email addresses matching your configured domains are automatically directed to your IdP for authentication.
## Notes
* SSO is configured per Profound organization: each organization needs its own connection.
* Subdomains cannot use the same SSO connection as the root domain: each subdomain needs its own connection.
* Contact [customer support](mailto:support@tryprofound.com) if you need assistance during setup.
# Enterprise Single Sign-On (SSO) overview
Source: https://docs.tryprofound.com/platform-config/authentication/sso-overview
Supported protocols, scope, and how to get started with SSO configuration
Enterprise Single Sign-On (SSO) lets users sign in with their corporate identity provider (IdP) credentials, such as Microsoft Entra ID, Okta, or Google Workspace. Profound keeps their user data synchronized with the IdP.
SSO is available for customers on the Enterprise plan. Setup requires the Admin role in your Profound organization. Learn more in [Roles and permissions](/platform-config/people/roles-and-permissions).
## Supported protocols
Profound supports multiple protocols for enterprise SSO, including Security Assertion Markup Language (SAML) and OpenID Connect (OIDC). Setup is tailored to your IdP, and custom SAML and OIDC connections are available if your provider isn't among the commonly supported options.
## Subdomain support
Authenticating with SSO requires the user's email domain to match the exact domain the connection is configured with. For example, a user with the email address `john-smith@tryprofound.com` can use SSO only with the `tryprofound.com` domain.
Subdomains (like `dev.tryprofound.com`) cannot use the same SSO connection as root domains, so each subdomain needs its own connection.
## SSO scope
SSO is configured per Profound organization. If your company operates multiple Profound organizations, each one needs its own SSO connection.
If your organizations share members, such as agency or contractor accounts, or have an otherwise non-standard configuration, contact your Engagement Manager for setup assistance.
## Getting started
Follow the [Configure SSO guide](/platform-config/authentication/configure-sso) to set up SSO for your organization. If you need help, contact [customer support](mailto:support@tryprofound.com).
# Add and manage team members
Source: https://docs.tryprofound.com/platform-config/people/add-and-manage-team-members
Invite team members to your Profound organization and manage their roles and access
Admins can add team members to their Profound organization from the **People** settings page. Each member gets a role that controls what they can see and do, and category access that controls which categories they can work in.
Only Admins can manage users and invitations. Learn more in [Roles and permissions](/platform-config/people/roles-and-permissions).
## Add a team member
1. Go to **Settings** in the settings icon menu at the bottom left of the platform.
2. Select **People** under **Organization** in the left navigation sidebar.
3. In the **Add SSO User** form, enter the new member's email address.
4. Select a role. For a breakdown of what each role can do, see [Roles and permissions](/platform-config/people/roles-and-permissions).
5. Under **Category Access**, select the categories the member can work in. Keep **Select all** to grant access to every category, or select individual categories.
6. Enter the member's first and last name (optional).
7. Select **Add User**.
The invitation appears in the **Pending** tab until the new member signs in.
### How the invitation is delivered
The new member receives an email from `no-reply@auth.mail.tryprofound.com` with a link to sign up. The link takes them to Profound, where they activate their account.
## Manage existing members
The **Active** tab of the People page lists every member of your organization, with their role, join date, and last sign-in. Search by name or filter by role to find a member.
* **Change a role**: Select the role next to the member's name and select a new one from the list.
* **Change category access**: Open the **...** action menu in the member's table row and select **Configure category access**.
* **Remove a member**: Open the **...** action menu in the member's table row and select **Remove from Team**.
## Manage pending invitations
The **Pending** tab lists invitations that haven't been accepted yet, with the assigned role and the invitation date. To cancel an invitation, open its **...** action menu and select **Revoke**.
# Roles and permissions
Source: https://docs.tryprofound.com/platform-config/people/roles-and-permissions
Learn about roles and permissions for team members in Profound
Profound uses role-based access control. Every team member in your organization has a role that determines which features they can see and what actions they can take.
To assign or change a role, see [Add and manage team members](/platform-config/people/add-and-manage-team-members).
## Roles at a glance
* **Admin**: Full access to every feature, plus organization management, including users and invitations, billing, and integrations. The only role that can change organization settings.
* **Editor**: Full access to product features, including managing prompts, assets, domains, and Knowledge Bases. No access to organization administration, except viewing integrations.
* **Member**: The standard role for day-to-day work. Views all analytics, works with Agents, Sheets, Profound Docs, and Skills, and uses Aim, but can't change the Answer Engine Insights (AEI) configuration or manage Knowledge Bases.
* **Viewer - AEI Only**: Views AEI data, Shopping, Pages, and Projects, and can view and create Dashboards, and view integrations. No access to Agents, Sheets, or Profound Docs.
* **Viewer - AEI + Ask**: Everything the Viewer - AEI Only role has, plus Aim for analytics and the ability to create and edit Skills.
* **Agent Operator**: Runs existing Agents, creates Agents from templates, and works with Sheets, Profound Docs, Prompt Volumes, Skills, and Aim for analytics. Can view Projects, Opportunities, and integrations. Can't create new Agents from scratch, edit Agents, or manage Sheets, and has no access to AEI data.
## Permissions by role
The tables below list each permission and the roles that have it.
### Organization and platform settings
Organization-level settings are reserved for Admins.
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| ------------------------------------ | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: |
| Manage users and invitations | | - | - | - | - | - |
| Manage and read billing | | - | - | - | - | - |
| Create agency workspaces | | - | - | - | - | - |
| Promote and extend agency workspaces | | - | - | - | - | - |
| View integrations | | | | | | |
| Manage integrations | | - | - | - | - | - |
| View Activity Logs | | - | - | - | - | - |
| View Team Performance center | | - | - | - | - | - |
### Answer Engine Insights
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| -------------- | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :------------: |
| View data | | | | | | - |
| Manage prompts | | | - | - | - | - |
| Manage assets | | | - | - | - | - |
| Manage domains | | | - | - | - | - |
### Analytics and reporting
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| -------------------------------- | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: |
| View Shopping | | | | | | - |
| View Dashboards | | | | | | - |
| Create Dashboards | | | | | | - |
| View Pages | | | | | | - |
| View Agent Analytics | | | | - | - | - |
| Manage Agent Analytics | | | - | - | - | - |
| View Prompt Volumes data | | | | - | - | |
| Manage Prompt Volumes watchlists | | | | - | - | |
### Agents and Sheets
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| ---------------------------- | :-------------------: | :-------------------: | :-------------------: | :---------------: | :----------------: | :-------------------: |
| View Agents | | | | - | - | |
| Edit Agents | | | | - | - | - |
| Create new Agents | | | | - | - | - |
| Create Agents from templates | | | | - | - | |
| Run Agents | | | | - | - | |
| View Sheets | | | | - | - | |
| Run Agents in Sheets | | | | - | - | |
| Manage and edit Sheets | | | | - | - | - |
### Profound Docs
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| ----------------------------------------------- | :-------------------: | :-------------------: | :-------------------: | :---------------: | :----------------: | :-------------------: |
| Create Docs | | | | - | - | |
| View Docs | | | | - | - | |
| Edit Docs | | | | - | - | |
| Share Docs with individuals or the organization | | | | - | - | |
| Export Docs | | | | - | - | |
| Use Aim in Docs | | | | - | - | |
### Knowledge Bases and Skills
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| -------------------------------------------------------- | :-------------------: | :-------------------: | :-------------------: | :---------------: | :-------------------: | :-------------------: |
| View Knowledge Bases | | | | - | - | |
| Edit and delete Knowledge Bases | | | - | - | - | - |
| Import from Notion or Google Drive into a Knowledge Base | | | - | - | - | - |
| Create and edit Skills | | | | - | | |
### Aim and Projects
| Permission | Admin | Editor | Member | Viewer - AEI Only | Viewer - AEI + Ask | Agent Operator |
| ------------------------- | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: | :-------------------: |
| Aim (analytics) | | | | - | | |
| Aim (build Agents) | | | | - | - | - |
| View Projects | | | | | | |
| Run an Agent in a Project | | | | - | - | - |
| View Opportunities | | | | - | - | |
# Authentication
Source: https://docs.tryprofound.com/rest-api/authentication
Learn how to authenticate API requests securely
The API is available to Enterprise plan customers only.
To access the API, you must request access through our support team.
## Overview
To authenticate your API requests, you need an API key. This key identifies and authorizes your requests, ensuring only authorized users can access resources.
Your API key provides access to all data available to your organization, including categories, regions, and category reports.
## Getting Your API Key
Follow these steps to obtain your API key:
Sign into the platform. In the bottom left, click on your name and select **Settings**
On the left sidebar, select **API Keys**. This will show your key generation portal and a table of your keys.
If you do not see the **API Keys** tab or are unable to access it, please contact [support](mailto:support@tryprofound.com) to request access.
In the top banner, enter a **key name** and select an **expiration date**. Note, *the key name must be greater than two characters*.
When ready, click **Create API Key** to generate the key. Once complete, the following dialog will be shown.
For added security, **you will not be able to retrieve your key again**. Be sure to copy and store your API key securely before proceeding.
That's it! You have now generated an API key that can be used to authenticate requests to the Profound API
Your key will be displayed in a table along with other keys you generate. Return to this page at any time to see your keys, check expiry dates, or revoke an existing key.
Your API key is sensitive information. Never share it publicly or commit it to version control. Store it securely and treat it like a password.
## Authentication Methods
You can authenticate your requests using either method below:
### Header Authentication (Recommended)
Include your API key in the `X-API-Key` header:
```http Header Method theme={null}
POST /v1/reports/visibility HTTP/1.1
Host: api.tryprofound.com
X-API-Key: your_api_key_here
Content-Type: application/json
```
```bash With cURL theme={null}
curl -X POST "https://api.tryprofound.com/v1/reports/visibility" \
-H "X-API-Key: your_api_key_here" \
-H "Content-Type: application/json"
```
## API Key Scope & Permissions
Your API key provides access to:
* **Organization Data**: All data belonging to your organization
* **Categories**: Available data categories and their metadata
* **Regional Data**: Location-based information and filters
* **Reports**: Generated reports and analytics for your categories
* **Raw Data**: Unprocessed data within your accessible categories
## Security Best Practices
* **Keep keys private**: Never expose API keys in client-side code or public repositories
* **Use environment variables**: Store keys in environment variables or secure configuration files
* **Rotate regularly**: Consider rotating your API keys periodically for enhanced security
* **Monitor usage**: Check your API usage regularly to detect any unauthorized access
## Authentication Errors
Common authentication errors and their meanings:
| Status Code | Error | Description |
| ----------------------- | ------------------------ | ---------------------------------------------------------- |
| `401 Unauthorized` | Invalid API key | The provided API key is incorrect or expired |
| `403 Forbidden` | Insufficient permissions | Your API key doesn't have access to the requested resource |
| `429 Too Many Requests` | Rate limit exceeded | You've exceeded your API key rate limit |
## Need Help?
If you encounter authentication issues or need to request API access, contact our support team for assistance.
# Changelog
Source: https://docs.tryprofound.com/rest-api/changelog
Track API changes, version history, and release notes
## Overview
This changelog tracks all changes, updates, and improvements to the Profound REST API. We document new features, bug fixes, breaking changes, deprecations, and security updates to help you stay informed and plan your integrations accordingly.
V2 now spans Answer Engine Insights and Agent Analytics reports under
`/v2/reports/visibility`, `/v2/reports/citations`,
`/v2/reports/sentiment`, `/v2/reports/query-fanouts`,
`/v2/reports/factcheck`, and `/v2/reports/factcheck/claims`, as well as
`/v2/prompts/answers`; each has a `/stream` SSE variant. V1 endpoints
remain active, including V1 report endpoints. For more information about
API versioning, see the [Introduction](/rest-api/introduction#api-versioning).
## Change categories
Changes are organized into the following categories:
* **Added** - New endpoints, features, or capabilities
* **Changed** - Modifications to existing endpoints or behavior
* **Deprecated** - Features that will be removed in a future version
* **Removed** - Features that have been removed
* **Fixed** - Bug fixes and corrections
* **Security** - Security improvements and vulnerability patches
* **Breaking** - Changes that require action to maintain compatibility
### Added
* New beta YouTube social reports: [Query YouTube Channels](/rest-api/reports/query-youtube-channels-v2) and [Query YouTube Videos](/rest-api/reports/query-youtube-videos-v2) for channel rollups, cited video rankings, and attribution modes.
* New endpoint: [Get Citation Tags](/api-reference/organization/get-category-citation-tags) - The custom citation tags defined for a category, as `{ value, name }` per tag. Pass any of these values to the new `citation_tag` filter below.
* New `citation_tag` filter on [`POST /v2/reports/citations`](/rest-api/reports/query-citations-v2) - Narrow a citations report to URLs carrying one or more of your custom tags (`is`/`in`; values in one `in` leaf are OR'd).
### Added
* New endpoint: [Get Citation Categories](/api-reference/organization/get-category-citation-categories) - The citation-category filter options for a category: the built-in buckets (Owned, Competition, Earned Media, Institution, PR Wire, Social, Other) plus any custom categories.
### Added
* New **beta** `/v2/reports` endpoints — a unified `{ info, data }` request/response shape, accepting names **or** UUIDs in filters, with cursor pagination and a `/stream` (SSE) variant:
* `POST /v2/reports/visibility` - Asset visibility, share of voice, and average position
* `POST /v2/reports/citations` - Domain and page citation counts, share, and rank
* `POST /v2/reports/sentiment` - Per-brand positive/negative sentiment with optional comparison periods
* `POST /v2/reports/query-fanouts` - Search queries an AI generates behind the scenes when answering a prompt
* `POST /v2/reports/factcheck` - FactCheck scores, with a `/stream` (SSE) variant
* `POST /v2/reports/factcheck/claims` - FactCheck inaccurate claims, with a `/stream` (SSE) variant
* New **beta** endpoint: `POST /v2/prompts/answers` - Raw per-execution rows (mentions, citations, search queries), with a `/stream` (SSE) variant
### Deprecated
* The V1 report endpoints (`POST /v1/reports/visibility`, `/citations`, `/sentiment`, `/sentiment-v2`, `/query-fanouts`) are being phased out in favor of the V2 equivalents above. They remain active; a sunset date will be announced before removal.
### Added
* New endpoint: [List Agents](/api-reference/agents/list-agents) - List agents available to your organization
* New endpoint: [Get an Agent](/api-reference/agents/get-an-agent) - Retrieve an agent and its schema details
* New endpoint: [Run an Agent](/api-reference/agents/run-an-agent) - Start a new run for an agent
* New endpoint: [Get an Agent Run](/api-reference/agents/get-an-agent-run) - Retrieve the status and result details for an agent run
### Deprecated
* Deprecated raw Agent Analytics endpoints:
* `POST /v1/logs/raw` - Get Logs
* `POST /v1/logs/raw/bots` - Get Bots
* Deprecation started on `2026-04-10`
* API keys created on or after `2026-04-10` can no longer access these endpoints
* Existing API keys created before `2026-04-10` can continue using these endpoints until the sunset date of `2026-06-10`
* Migrate to the V2 aggregated report endpoints instead:
* `POST /v2/reports/bots` for bot traffic reporting
* `POST /v2/reports/referrals` for referral traffic reporting
* For examples using the replacement endpoints, see [Agent Analytics V2](/rest-api/examples/agent-analytics)
### Added
* New `/v2/reports` endpoints with **hourly granularity**, bucketed by UTC hour — see [Agent Analytics V2](/rest-api/examples/agent-analytics)
* `POST /v2/reports/bots` - Bot traffic data at hourly resolution
* `POST /v2/reports/referrals` - Referral traffic data at hourly resolution, including UTM and referrer distinction
* Because V2 uses UTC hour buckets rather than EST day buckets, users in any timezone can now align queries to their own local calendar days
### Added
* New endpoint: Get [Referrals Report](/api-reference/reports/get-referrals-report-v1) - Retrieve referral traffic data from daily aggregated reports
* New endpoint: Get [Bots Report](/api-reference/reports/get-bots-report-v1) - Retrieve bot traffic analytics with metrics for citations, indexing, training, and visit counts
### Changed
* Reorganized example documentation structure under new [Example Requests](/rest-api/examples/example) tab
### Removed
* Legacy examples page
### Added
* New endpoint: [Get Personas](/api-reference/organization/get-personas) - Retrieve all personas associated with your organization
* New endpoint: [Get Category Personas](/api-reference/organization/get-category-personas) - Retrieve all personas associated to the given category
* `persona` dimension to citations, visibility and sentiment reports
* `persona` to the prompt answers
* `model_id` to the prompt answers
* `sentiment_themes` to the prompt answers, deprecating `themes`. `sentiment_themes` returns the theme and its sentiment
### Changed
* Require a non-empty list value when using the `in` or `not_in` filter operator
* `created_at` field is not allowed to be disabled
### Fixed
* Avoid exporting duplicate prompts in the prompt answers.
### Added
* New endpoint: [Get Category Assets](/api-reference/organization/get-category-assets) - Retrieve assets associated with a specific category
* New endpoint: [Get Assets](/api-reference/organization/get-assets) - Retrieve all assets associated with your organization
* `asset_id` dimension in [Query Visibility](/api-reference/reports/query-visibility) and [Query Sentiment](/api-reference/reports/query-sentiment)
### Changed
* Require `hostname`, `path`, `root_domain` and `url` to be included as dimensions when used as filters
### Fixed
* `contains` filter not being applied correctly
* Typo in sentiment metric field name
* **Before:** `ocurrences`
* **After:** `occurrences`
* Filters containing UUID's not being applied correctly
* Incorrect handling of mixed timezone and non-timezone values in `start_date` and `end_date` filters
# Date Ranges & Timezones
Source: https://docs.tryprofound.com/rest-api/date-ranges
Understanding how to work with dates and timezones in the API
## Overview
All data in our system is stored in UTC, but our processing runs on an EST (Eastern Standard Time) schedule. Understanding how date ranges work is critical to querying the correct data for your use case.
Incorrect timezone handling is the most common cause of missing or unexpected data in API responses. Please read this guide carefully.
## System Behavior
### Data Processing Schedule
Our system processes data according to the EST timezone:
* The "day" of January 1st EST starts at **00:00 EST** (05:00 UTC)
* The "day" of January 1st EST ends at **23:59 EST** (04:59 UTC next day)
All data is stored with UTC timestamps in our database.
### Date Format Support
The API accepts dates in multiple formats:
1. **Date only** (recommended for daily queries): `2025-01-01`
2. **Date and time without timezone**: `2025-01-01T00:00:00`
3. **Date and time with UTC timezone**: `2025-01-01T05:00:00Z`
## How Dates Are Interpreted
### Without Timezone Specification
When you provide a date **without a timezone** (no `Z` suffix), the API interprets it as **EST**:
```json theme={null}
{
"start_date": "2025-01-01",
"end_date": "2025-01-31"
}
```
**What happens:**
* `2025-01-01` → Interpreted as `2025-01-01T00:00:00 EST` → Converted to `2025-01-01T05:00:00Z` UTC
* `2025-01-31` → Interpreted as `2025-01-31T00:00:00 EST` → Converted to `2025-01-31T05:00:00Z` UTC
This matches how our system defines "days" and is the **recommended approach** for most use cases.
### With UTC Timezone (Z suffix)
When you provide a date **with the Z suffix**, the API interprets it as **literal UTC**:
```json theme={null}
{
"start_date": "2025-01-01T00:00:00Z",
"end_date": "2025-02-01T00:00:00Z"
}
```
**What happens:**
* `2025-01-01T00:00:00Z` → Used as-is in UTC
* `2025-02-01T00:00:00Z` → Used as-is in UTC
Using UTC timestamps (with Z) requires you to manually convert from EST to UTC. This approach exists for backwards compatibility but is **not recommended** for new integrations.
## Examples
### Correct: Query January 2025 data (EST days)
```json theme={null}
{
"start_date": "2025-01-01",
"end_date": "2025-02-01"
}
```
This returns all data from:
* Start: January 1st, 00:00 EST (05:00 UTC on Jan 1st)
* End: February 1st, 00:00 EST (05:00 UTC on Feb 1st)
The range is inclusive (`<=`), but since data typically doesn't have timestamps exactly at 00:00, this effectively captures all of January.
### Incorrect: Query January 2025 with UTC midnight
```json theme={null}
{
"start_date": "2025-01-01T00:00:00Z",
"end_date": "2025-02-01T00:00:00Z"
}
```
This returns data from:
* Start: December 31st, 19:00 EST (00:00 UTC on Jan 1st)
* End: January 31st, 19:00 EST (00:00 UTC on Feb 1st)
**Problem:** You're missing 5 hours at the start and including 5 hours you don't want at the end.
### Correct: Query January 2025 with UTC (manual conversion)
If you must use UTC timestamps, you need to account for the EST offset:
```json theme={null}
{
"start_date": "2025-01-01T05:00:00Z",
"end_date": "2025-02-01T05:00:00Z"
}
```
This correctly captures all of January (EST days), but requires manual timezone math.
## Time Ranges
### Date-only format defaults to midnight
When using date-only format, times default to `00:00:00`:
```json theme={null}
{
"start_date": "2025-01-01" // Equivalent to 2025-01-01T00:00:00 EST
}
```
### Specifying exact times
You can specify exact times for more granular queries:
```json theme={null}
{
"start_date": "2025-01-01T08:00:00", // 8 AM EST
"end_date": "2025-01-01T17:00:00" // 5 PM EST
}
```
This queries data from 8 AM to 5 PM EST on January 1st.
### Date range behavior
Date ranges are **inclusive** on both ends `(start <= x <= end)`:
```json theme={null}
{
"start_date": "2025-01-01",
"end_date": "2025-01-02"
}
```
This includes:
* All of January 1st (from 00:00 EST onwards)
* January 2nd at exactly 00:00 EST
* Since data is timestamped throughout the day, there typically isn't data exactly at 00:00, so in practice this captures all of January 1st
To query a single day, set `end_date` to the next day at 00:00.
## Best Practices
**Recommended:** Use date-only format without timezone for daily queries
```json theme={null}
{
"start_date": "2025-01-01",
"end_date": "2025-02-01"
}
```
**Recommended:** Use datetime without timezone for intraday queries
```json theme={null}
{
"start_date": "2025-01-15T09:00:00",
"end_date": "2025-01-15T17:00:00"
}
```
**Recommended:** Use datetime without timezone for hourly report queries (via [Agent Analytics](/rest-api/examples/agent-analytics) **V2 (hourly)** tab)
```json theme={null}
{
"start_date": "2025-01-15T14:00:00",
"end_date": "2025-01-15T14:59:59"
}
```
**Fractional-offset timezone users:** When querying at hour-level granularity with `/v2/reports/*`, query 2 consecutive hours to get complete data for a single local hour. See [Fractional-Offset Timezones](#fractional-offset-timezones) for details.
**Avoid:** Using Z suffix unless you understand UTC offset implications
```json theme={null}
{
"start_date": "2025-01-01T00:00:00Z", // Probably not what you want
"end_date": "2025-02-01T00:00:00Z"
}
```
## Daylight Saving Time
EST observes Daylight Saving Time (DST):
* **Standard Time (EST):** UTC-5 (typically November - March)
* **Daylight Time (EDT):** UTC-4 (typically March - November)
The API automatically handles DST transitions. When you specify dates without timezone, the conversion to UTC accounts for whether DST was active on that date.
**Example during DST:**
```json theme={null}
{
"start_date": "2025-07-01" // Interpreted as EDT (UTC-4)
}
```
→ Converted to `2025-07-01T04:00:00Z` UTC (not 05:00 because of DST)
## Fractional-Offset Timezones
Some timezones use fractional UTC offsets rather than whole-hour offsets:
| Timezone | UTC Offset |
| ------------------------- | ---------- |
| India Standard Time (IST) | +5:30 |
| Afghanistan Time (AFT) | +4:30 |
| Myanmar Time (MMT) | +6:30 |
| Nepal Time (NPT) | +5:45 |
| Chatham Islands (CHAST) | +12:45 |
| Marquesas Islands (MART) | -9:30 |
Because hourly buckets are aligned to whole-hour UTC boundaries, a single local hour in these timezones will always straddle two hourly buckets. To get complete data for any given local hour, you must query **2 consecutive hours**.
### Example: Querying for 2:00 PM IST
IST is UTC+5:30, so 2:00 PM IST = 08:30 UTC. The hour from 2:00 PM to 3:00 PM IST (08:30 - 09:30 UTC) spans two UTC hour buckets:
* **08:00 - 08:59 UTC** (contains the first 30 minutes: 2:00 PM - 2:30 PM IST)
* **09:00 - 09:59 UTC** (contains the last 30 minutes: 2:30 PM - 3:00 PM IST)
To retrieve the full hour, query both buckets:
```json theme={null}
{
"start_date": "2025-01-15T08:00:00Z",
"end_date": "2025-01-15T09:59:59Z"
}
```
This applies when querying at **hour-level granularity** via `/v2/reports/*`. If you are in a fractional-offset timezone and request data by hour, always request 2 consecutive hours to avoid missing data that falls in the adjacent bucket.
## Troubleshooting
### Missing data at day boundaries
**Problem:** You're querying January 1st but missing the first or last few hours.
**Solution:** Make sure you're not using the `Z` suffix. Use `"start_date": "2025-01-01"` instead of `"start_date": "2025-01-01T00:00:00Z"`.
### Data from previous/next day appearing
**Problem:** Your daily query includes data from adjacent days.
**Solution:** You're likely using `Z` suffix with midnight UTC, which doesn't align with EST days. Remove the timezone suffix.
### Unexpected DST behavior
**Problem:** Your queries have a 1-hour difference during DST transitions.
**Solution:** Let the API handle DST automatically by using dates without timezone. If you must use UTC, remember the offset changes between EST (-5) and EDT (-4).
## Future Changes
In a future version of the API, we plan to support full ISO 8601 timezone offsets (e.g., `-05:00`, `+09:00`) to enable multi-timezone queries. Dates without timezone specification will be deprecated at that time.
For now, the recommended approach is to use dates without timezone and let the API handle the EST conversion for you.
# Agent Analytics
Source: https://docs.tryprofound.com/rest-api/examples/agent-analytics
Sample requests for Agent Analytics endpoints.
This guide provides practical examples of common API requests. All examples use JSON format and require authentication via API key.
# Reports
Examples for **V1** report endpoints (`/v1/reports/*`): daily pre-aggregated data in EST.
For hourly granularity, use the **Hourly Reports (V2)** tab above.
Raw Agent Analytics log endpoints are retired. For raw per-execution
prompt-answer rows, use `POST /v2/prompts/answers`. For bot and referral
traffic, use the aggregated `/v2/reports/bots` and `/v2/reports/referrals`
endpoints.
* **Capacity:** Full date ranges in one request using aggregated report endpoints.
* **Granularity:** Data is bucketed by day. Timestamps are normalized to the start of each day in EST.
## Bot Reports
Get a count of visits by bot type:
```http theme={null}
POST /v1/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"metrics": ["citations", "training", "indexing"]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
20640,
8450,
3646
],
"dimensions": []
}
]
}
```
Get a count of ChatGPT citations by day:
Note you can easily retrieve the full daily list broken down by bot by substituting:
```
"dimensions": ["date", "bot_name"],
"filters": [],
```
```http theme={null}
POST /v1/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["date"],
"filters": [
{"field": "bot_name", "operator": "is", "value": "ChatGPT-User"}
],
"order_by": {
"date": "desc"
},
"metrics": ["citations"]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
2698
],
"dimensions": [
"2025-12-18"
]
},
{
"metrics": [
2847
],
"dimensions": [
"2025-12-17"
]
},
{
"metrics": [
2986
],
"dimensions": [
"2025-12-16"
]
},
{
"metrics": [
3029
],
"dimensions": [
"2025-12-15"
]
},
{
"metrics": [
2075
],
"dimensions": [
"2025-12-14"
]
},
{
"metrics": [
1881
],
"dimensions": [
"2025-12-13"
]
},
{
"metrics": [
2717
],
"dimensions": [
"2025-12-12"
]
}
]
}
```
Get a count of page visits by bot type, scoped to a provider:
Note the OpenAI **Platforms** selection in the top right.
See metrics for all providers by removing the filter.
```http theme={null}
POST /v1/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["path"],
"filters": [
{"field": "bot_provider", "operator": "is", "value": "openai"}
],
"order_by": {"citations": "desc"},
"metrics": ["citations", "indexing", "training"],
"pagination": {
"limit": 10,
"offset": 0
}
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
1255,
1614,
38
],
"dimensions": [
"/"
]
},
{
"metrics": [
643,
5,
1
],
"dimensions": [
"/guides/generative-engine-optimization-geo-guide-2025"
]
},
{
"metrics": [
603,
18,
3
],
"dimensions": [
"/blog/now-tracking-gpt-5-2-in-chatgpt"
]
},
{
"metrics": [
584,
7,
3
],
"dimensions": [
"/blog/ai-platform-citation-patterns"
]
},
{
"metrics": [
445,
1,
0
],
"dimensions": [
"/blog/best-generative-engine-optimization-tools"
]
},
{
"metrics": [
396,
14,
1
],
"dimensions": [
"/profound-index"
]
},
{
"metrics": [
385,
6,
1
],
"dimensions": [
"/guides/what-is-answer-engine-optimization"
]
},
{
"metrics": [
376,
2,
0
],
"dimensions": [
"/blog/semrush-ai-visibility-toolkit-review"
]
},
{
"metrics": [
372,
5,
2
],
"dimensions": [
"/blog/understanding-grok-a-comprehensive-guide-to-grok-websearch-grok-deepsearch"
]
},
{
"metrics": [
371,
7,
1
],
"dimensions": [
"/blog/choosing-ai-visibility-provider"
]
}
]
}
```
## Referral Reports
Get a count of referrals broken down by platform:
Note:
`other` represents referrals from **Traditional Sources**, e.g. LinkedIn, Facebook, etc.
`internal` represents referrals from within your website, e.g. a blog post linking to another blog post.
```http theme={null}
POST /v1/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["referral_source"],
"filters": [
{"field": "referral_source", "operator": "not_in", "value": ["none", "internal"]}
],
"metrics": ["visits"]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
222022
],
"dimensions": [
"other"
]
},
{
"metrics": [
5171
],
"dimensions": [
"openai"
]
},
{
"metrics": [
102
],
"dimensions": [
"perplexity"
]
},
{
"metrics": [
39
],
"dimensions": [
"gemini"
]
},
{
"metrics": [
22
],
"dimensions": [
"anthropic"
]
},
{
"metrics": [
2
],
"dimensions": [
"deepseek"
]
}
]
}
```
Get a count of referrals from AI bots broken down by day:
```http theme={null}
POST /v1/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["date"],
"filters": [
{"field": "referral_source", "operator": "not_in", "value": ["none", "other", "internal"]}
],
"order_by": {"date": "desc"},
"metrics": ["visits"]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
977
],
"dimensions": [
"2025-12-18"
]
},
{
"metrics": [
906
],
"dimensions": [
"2025-12-17"
]
},
{
"metrics": [
719
],
"dimensions": [
"2025-12-16"
]
},
{
"metrics": [
571
],
"dimensions": [
"2025-12-15"
]
},
{
"metrics": [
665
],
"dimensions": [
"2025-12-14"
]
},
{
"metrics": [
655
],
"dimensions": [
"2025-12-13"
]
},
{
"metrics": [
844
],
"dimensions": [
"2025-12-12"
]
}
]
}
```
Get a count of referrals broken down by a given page:
Note `/blog` in the search bar.
**% of Bot Referrals** can be calculated by summing the total number of referrals, and dividing each bot's referrals by the total.
```http theme={null}
POST /v1/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["path"],
"filters": [
{"field": "referral_source", "operator": "not_in", "value": ["none", "other", "internal"]},
{"field": "path", "operator": "contains", "value": "/blog"}
],
"metrics": ["visits"],
"order_by": {"visits": "desc"},
"pagination": {"limit": 10, "offset": 0}
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
915
],
"dimensions": [
"/blog/ai-platform-citation-patterns"
]
},
{
"metrics": [
350
],
"dimensions": [
"/blog/bring-profound-data-directly-into-your-ai-workflow-with-mcp"
]
},
{
"metrics": [
99
],
"dimensions": [
"/blog/citation-overlap-strategy"
]
},
{
"metrics": [
87
],
"dimensions": [
"/blog/the-data-on-reddit-and-ai-search"
]
},
{
"metrics": [
65
],
"dimensions": [
"/blog/best-generative-engine-optimization-tools"
]
},
{
"metrics": [
58
],
"dimensions": [
"/blog/chatgpt-entity-update"
]
},
{
"metrics": [
56
],
"dimensions": [
"/blog/prompt-volumes-the-new-way-to-see-what-customers-ask-answer-engines"
]
},
{
"metrics": [
50
],
"dimensions": [
"/blog/seeing-what-customers-see-direct-ai-search-engine-monitoring-vs-api-limitations"
]
},
{
"metrics": [
40
],
"dimensions": [
"/blog/choosing-ai-visibility-provider"
]
},
{
"metrics": [
33
],
"dimensions": [
"/blog/ai-search-volatility"
]
}
]
}
```
Get a count of referrals broken down by bot:
**% of Referrals** here means the proportion of referred visits from non-internal sources that came from this bot.
To calculate this, sum the total number of referrals in the response:
`total_referrals = 222126 + 5172 + 102 + 39 + 22 + 2 = 227481`
Then, for each bot, divide its referrals by the total:
`ChatGPT % = (5172 / 227481) * 100 = 2.27%`
...
```http theme={null}
POST /v1/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["referral_source"],
"filters": [
{"field": "referral_source", "operator": "not_in", "value": ["none", "internal"]}
],
"metrics": ["visits"],
"order_by": {"visits": "desc"}
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [
222126
],
"dimensions": [
"other"
]
},
{
"metrics": [
5172
],
"dimensions": [
"openai"
]
},
{
"metrics": [
102
],
"dimensions": [
"perplexity"
]
},
{
"metrics": [
39
],
"dimensions": [
"gemini"
]
},
{
"metrics": [
22
],
"dimensions": [
"anthropic"
]
},
{
"metrics": [
2
],
"dimensions": [
"deepseek"
]
}
]
}
```
V2 endpoints provide reports at **hourly granularity**, with data bucketed by UTC hour. They support all the same dimensions, metrics and filters as V1, plus new fields unique to the hourly tables - **UTM** and **referral** traffic distinction.
V1 daily aggregates are fixed to ET, which means users in other timezones had no way to get data bucketed into their own local days. V2 solves this: because data is bucketed by UTC hour, you can convert your local day boundaries to UTC and query data that lines up with your own calendar days.
**V1 vs V2:** Use the **V1 (daily)** tab for daily pre-aggregated reports
(EST-based). V2 is for hour-level granularity (UTC). Raw per-execution
prompt-answer rows are available through `POST /v2/prompts/answers`.
**Fractional-offset timezones:** If your local timezone uses a fractional UTC offset (e.g. IST +5:30, Nepal +5:45), a single local hour spans two UTC hour buckets. When querying at hour-level granularity, request **2 consecutive hours** to get complete data for that local hour. See [Date Ranges & Timezones](/rest-api/date-ranges#fractional-offset-timezones) for details.
## Bot Reports
Returns bot traffic data aggregated from the hourly bot breakdown table.
Get a count of visits by bot type:
```http theme={null}
POST /v2/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"metrics": ["citations", "training", "indexing"]
}
```
Get a count of ChatGPT citations by day:
```http theme={null}
POST /v2/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["date"],
"filters": [
{ "field": "bot_name", "operator": "is", "value": "ChatGPT-User" }
],
"order_by": { "date": "desc" },
"metrics": ["citations"]
}
```
Get top paths by citations for a specific provider:
```http theme={null}
POST /v2/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["path"],
"filters": [
{ "field": "bot_provider", "operator": "is", "value": "openai" }
],
"order_by": { "citations": "desc" },
"metrics": ["citations", "indexing", "training"],
"pagination": { "limit": 10, "offset": 0 }
}
```
Get hourly bot traffic breakdown for a UTC day. Use UTC timestamps to align the query to your local calendar day:
```http theme={null}
POST /v2/reports/bots HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-16T00:00:00Z",
"end_date": "2025-12-16T23:59:59Z",
"dimensions": ["hour"],
"metrics": ["count", "citations"],
"order_by": { "hour": "asc" }
}
```
### Request body
| Field |
Type |
Required |
Default |
Description |
domain |
string |
yes |
- |
Domain to query (e.g. [www.tryprofound.com](http://www.tryprofound.com)) |
start\_date |
string |
yes |
- |
Start date in UTC. Accepts YYYY-MM-DD, YYYY-MM-DD HH:MM, YYYY-MM-DD HH:MM:SS, or full ISO timestamp |
end\_date |
string |
no |
now (UTC) |
End date in UTC. Same formats as start\_date |
metrics |
string\[] |
yes |
- |
One or more metrics to return (see below) |
dimensions |
string\[] |
no |
\[] |
Fields to group results by (see below) |
filters |
filter\[] |
no |
\[] |
Filters to narrow results (see below) |
date\_interval |
string |
no |
"day" |
Bucket size for date dimension: "hour" or "day" |
order\_by |
object |
no |
first metric desc |
Map of field -> "asc" or "desc" |
pagination |
object |
no |
limit: 10000, offset: 0 |
Pagination settings |
### Metrics
| Metric | Description |
| ------------ | ------------------------------------------------------------------------- |
| `count` | Total unique bot visits (all bot types) |
| `citations` | Unique visits from AI assistant bots (e.g. ChatGPT-User, Perplexity-User) |
| `indexing` | Unique visits from web indexing bots (e.g. Googlebot, bingbot) |
| `training` | Unique visits from AI training bots (e.g. GPTBot, ClaudeBot) |
| `last_visit` | Most recent visit timestamp |
### Dimensions
| Dimension | Description |
| -------------- | ---------------------------------------------------------------------------------------------- |
| `date` | Bucketed by `date_interval` (day or hour). UTC-based |
| `hour` | Raw UTC hour bucket — equivalent to `date` + `date_interval: "hour"` with no extra aggregation |
| `path` | URL path |
| `bot_name` | Bot name (e.g. `ChatGPT-User`, `GPTBot`) |
| `bot_provider` | Bot provider (e.g. `openai`, `anthropic`) |
| `bot_type` | Bot category: `ai_assistant`, `index`, `ai_training`, `ai_agent` |
### Filters
| Field | Operators | Values |
| -------------- | ---------------------------------------------------------- | -------------------------------------------------- |
| `path` | `is`, `not_is`, `contains`, `not_contains`, `in`, `not_in` | URL path string |
| `bot_name` | `is`, `not_is`, `contains`, `not_contains`, `in`, `not_in` | Bot name string |
| `bot_provider` | `is`, `not_is`, `contains`, `not_contains`, `in`, `not_in` | Provider string |
| `bot_type` | `is`, `not_is`, `in`, `not_in` | `ai_assistant`, `index`, `ai_training`, `ai_agent` |
***
## Referral Reports
Returns referral traffic data aggregated from the hourly referral breakdown table.
Get a count of referrals broken down by platform (excluding internal traffic):
```http theme={null}
POST /v2/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["referral_source"],
"filters": [
{ "field": "referral_source", "operator": "not_in", "value": ["none", "internal"] }
],
"metrics": ["visits"]
}
```
Get a count of referrals from AI bots broken down by day:
```http theme={null}
POST /v2/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["date"],
"filters": [
{ "field": "referral_source", "operator": "not_in", "value": ["none", "other", "internal"] }
],
"order_by": { "date": "desc" },
"metrics": ["visits"]
}
```
Get top blog paths by external referral visits:
```http theme={null}
POST /v2/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["path"],
"filters": [
{ "field": "referral_source", "operator": "not_in", "value": ["none", "other", "internal"] },
{ "field": "path", "operator": "contains", "value": "/blog" }
],
"metrics": ["visits"],
"order_by": { "visits": "desc" },
"pagination": { "limit": 10, "offset": 0 }
}
```
Get top referral sources ranked by visits:
```http theme={null}
POST /v2/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-12",
"end_date": "2025-12-18",
"dimensions": ["referral_source"],
"filters": [
{ "field": "referral_source", "operator": "not_in", "value": ["none", "internal"] }
],
"metrics": ["visits"],
"order_by": { "visits": "desc" }
}
```
Get UTM referral traffic by Hour:
```http theme={null}
POST /v2/reports/referrals HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"domain": "www.tryprofound.com",
"start_date": "2025-12-16",
"end_date": "2025-12-17",
"dimensions": ["hour"],
"filters": [
{ "field": "referral_type", "operator": "is", "value": "utm" }
],
"metrics": ["visits"],
"order_by": { "hour": "asc" }
}
```
### Request body
| Field |
Type |
Required |
Default |
Description |
domain |
string |
yes |
- |
Domain to query |
start\_date |
string |
yes |
- |
Start date in UTC. Accepts YYYY-MM-DD, YYYY-MM-DD HH:MM, YYYY-MM-DD HH:MM:SS, or full ISO timestamp |
end\_date |
string |
no |
now (UTC) |
End date in UTC. Same formats as start\_date |
metrics |
string\[] |
yes |
- |
One or more metrics to return (see below) |
dimensions |
string\[] |
no |
\[] |
Fields to group results by (see below) |
filters |
filter\[] |
no |
\[] |
Filters to narrow results (see below) |
date\_interval |
string |
no |
"day" |
Bucket size for date dimension: "hour" or "day" |
order\_by |
object |
no |
first metric desc |
Map of field -> "asc" or "desc" |
pagination |
object |
no |
limit: 10000, offset: 0 |
Pagination settings |
### Metrics
| Metric | Description |
| ------------ | --------------------------- |
| `visits` | Unique page visits |
| `last_visit` | Most recent visit timestamp |
### Dimensions
| Dimension | Description |
| ----------------- | ---------------------------------------------------------------------------------------------- |
| `date` | Bucketed by `date_interval` (day or hour). UTC-based |
| `hour` | Raw UTC hour bucket — equivalent to `date` + `date_interval: "hour"` with no extra aggregation |
| `path` | URL path |
| `referral_source` | Referral source (e.g. `openai`, `perplexity`, `anthropic`, `other`, `internal`, `none`) |
| `referral_type` | Traffic category: `internal`, `referer`, `utm`, `none` |
### Filters
| Field | Operators | Values |
| ----------------- | ---------------------------------------------------------- | ------------------------------------ |
| `path` | `is`, `not_is`, `contains`, `not_contains`, `in`, `not_in` | URL path string |
| `referral_source` | `is`, `not_is`, `contains`, `not_contains`, `in`, `not_in` | Referral source string |
| `referral_type` | `is`, `not_is`, `in`, `not_in` | `internal`, `referer`, `utm`, `none` |
***
## Raw Data
The raw Agent Analytics endpoints `POST /v1/logs/raw` and
`POST /v1/logs/raw/bots` were retired on 2026-06-10. Use the [V2 bot and
referral report examples](/rest-api/examples/agent-analytics) for aggregated traffic data,
or [V2 prompt answers](/rest-api/reports/query-answers-v2) for raw
per-execution rows.
# Agents
Source: https://docs.tryprofound.com/rest-api/examples/agents
Sample requests for Agent endpoints.
This guide provides practical examples of common Agent API requests. All examples require authentication via API key.
Replace `your_api_key`, `your_agent_id`, and `your_run_id` with your actual values. Use the list endpoint first to discover the agents available to your organization.
## Starter Template walkthrough
Suppose you created an agent using **Profound's Starter Template**. This agent has one required text input labeled **Any Text (This is an example input)**.
This is the typical flow:
1. Use [**List Agents**](/api-reference/agents/list-agents) to find the agent ID.
2. Use [**Get an Agent**](/api-reference/agents/get-an-agent) to inspect the input schema.
3. Use [**Run an Agent**](/api-reference/agents/run-an-agent) with an `inputs` object keyed by the schema's property names.
4. Use [**Get an Agent Run**](/api-reference/agents/get-an-agent-run) to check whether the run succeeded or failed.
### 1. List Agents
First, identify the agent you want to run:
```http theme={null}
GET /v1/agents?statuses=published&limit=100 HTTP/1.1
X-API-Key: your_api_key
```
```json theme={null}
{
"data": [
{
"id": "your_agent_id",
"organization_id": "your_organization_id",
"name": "Starter Template",
"status": "published",
"created_at": "2026-04-24T19:03:15.459951Z",
"description": "This template is a simple starter agent that helps you get familiar with how the tool works. Try it out, customize it, and then build your own!"
}
]
}
```
### 2. Get an Agent
Next, retrieve the agent and inspect its schema. This response gives you the agent's input schema and output schema as JSON Schema. You use `schema.input` to determine which fields are required and which variable IDs to send in the `inputs` object when you run the agent. You can also use `schema.output` to understand the shape of the result you'll get back from the run.
```http theme={null}
GET /v1/agents/your_agent_id?version=published HTTP/1.1
X-API-Key: your_api_key
```
```json theme={null}
{
"id": "your_agent_id",
"organization_id": "your_organization_id",
"name": "Starter Template",
"status": "published",
"created_at": "2026-04-24T19:03:15.459951Z",
"description": "This template is a simple starter agent that helps you get familiar with how the tool works. Try it out, customize it, and then build your own!",
"schema": {
"input": {
"type": "object",
"properties": {
"your_input_variable_id": {
"type": "string",
"title": "Any Text (This is an example input)"
}
},
"additionalProperties": false,
"description": "Provide inputs as an object keyed by variable ID.",
"required": ["your_input_variable_id"]
},
"output": {
"type": "object",
"properties": {
"your_output_variable_id": {
"type": "string",
"title": "Example LLM Output"
}
},
"additionalProperties": false,
"description": "Agent outputs are returned as an object keyed by variable ID."
}
}
}
```
The `inputs` object must use the schema property key as the field name. In this case, the required input key is `your_input_variable_id`, not the human-readable label.
### 3. Run an Agent
Now start a run using that input key:
```http theme={null}
POST /v1/agents/your_agent_id/runs HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"inputs": {
"your_input_variable_id": ""
}
}
```
```json theme={null}
{
"id": "your_run_id",
"agent_id": "your_agent_id",
"status": "queued",
"started_at": "2026-04-24T19:08:34.495737Z"
}
```
This endpoint returns `202 Accepted`. A successful submission only means the run was accepted; you still need to fetch the run to see whether it ultimately succeeded or failed.
### 4. Get an Agent Run
Finally, fetch the run result:
```http theme={null}
GET /v1/agents/your_agent_id/runs/your_run_id HTTP/1.1
X-API-Key: your_api_key
```
```json theme={null}
{
"id": "your_run_id",
"agent_id": "your_agent_id",
"status": "succeeded",
"started_at": "2026-04-24T20:53:08.241633Z",
"finished_at": "2026-04-24T20:53:09.314671Z",
"outputs": {
"your_output_variable_id": ""
}
}
```
# Answer Engine Insights
Source: https://docs.tryprofound.com/rest-api/examples/answer-engine-insights
Sample requests for Answer Engine Insights endpoints.
This guide provides practical examples of common API requests. All examples use JSON format and require authentication via API key.
Replace `your_api_key`, `your_category_id`, and `your_company_name` with your
actual values. Category IDs can be obtained from `/v1/org/categories`.
All examples use simplified date formats. For production use, please read [Date Ranges & Timezones](/rest-api/date-ranges) to understand timezone handling and avoid common pitfalls with date parameters.
## Visibility Reports
Retrieve visibility metrics and performance data for companies within specific categories. See the full [endpoint reference](/api-reference/reports/query-visibility) for all available metrics, dimensions, and filters.
Track a specific company's visibility performance with daily granularity:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"date_interval": "day",
"metrics": ["visibility_score"],
"dimensions": ["date"],
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.45], "dimensions": ["2026-01-01"] },
{ "metrics": [0.48], "dimensions": ["2026-01-02"] },
{ "metrics": [0.52], "dimensions": ["2026-01-03"] },
{ "metrics": [0.51], "dimensions": ["2026-01-04"] },
{ "metrics": [0.55], "dimensions": ["2026-01-05"] },
{ "metrics": [0.58], "dimensions": ["2026-01-06"] },
{ "metrics": [0.60], "dimensions": ["2026-01-07"] }
]
}
```
**Use case:** Monitor daily performance changes and identify trends.
Get the top 5 companies with the highest visibility score in a category:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["visibility_score"],
"dimensions": ["asset_name"],
"pagination": {
"limit": 5
}
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.583], "dimensions": ["Company A"] },
{ "metrics": [0.343], "dimensions": ["Company B"] },
{ "metrics": [0.231], "dimensions": ["Company C"] },
{ "metrics": [0.216], "dimensions": ["Company D"] },
{ "metrics": [0.173], "dimensions": ["Company E"] }
]
}
```
**Use case:** Identify market leaders and benchmark against top performers.
Analyze visibility score and share of voice across different platforms for a specific company:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["visibility_score", "share_of_voice"],
"dimensions": ["model"],
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.72, 0.15], "dimensions": ["ChatGPT"] },
{ "metrics": [0.65, 0.12], "dimensions": ["Perplexity"] },
{ "metrics": [0.58, 0.09], "dimensions": ["Gemini"] },
{ "metrics": [0.41, 0.06], "dimensions": ["Claude"] }
]
}
```
**Use case:** Understand platform-specific performance and opportunities.
Analyze visibility score and share of voice across different regions for a specific company:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["visibility_score", "share_of_voice"],
"dimensions": ["region"],
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [0.85, 0.32],
"dimensions": ["North America"]
},
{
"metrics": [0.72, 0.28],
"dimensions": ["Europe"]
}
]
}
```
**Use case:** Identify regional strengths and weaknesses in visibility score and share of voice.
To replicate the Average Position view in the platform, two API calls are needed. The platform shows average position for the top assets ranked by visibility — not all assets sorted by position.
**Step 1:** Get the top assets by visibility score:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["visibility_score"],
"dimensions": ["asset_name"],
"order_by": { "visibility_score": "desc" },
"pagination": { "limit": 50 }
}
```
**Step 2:** Use those asset names to get their average position:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["average_position"],
"dimensions": ["asset_name"],
"filters": [
{
"field": "asset_name",
"operator": "in",
"value": ["Company A", "Company B", "Company C", "Company D", "Company E"]
}
],
"order_by": { "average_position": "asc" }
}
```
`"asc"` ordering — lower position is better, so #1 rank has the lowest value. The `"in"` filter uses the asset names returned from Step 1.
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [1.6], "dimensions": ["Company A"] },
{ "metrics": [2.0], "dimensions": ["Company B"] },
{ "metrics": [2.2], "dimensions": ["Company C"] },
{ "metrics": [3.2], "dimensions": ["Company D"] },
{ "metrics": [3.5], "dimensions": ["Company E"] }
]
}
```
**Use case:** Identify top-ranked companies and benchmark against competitors.
Track a specific company's average position with daily granularity:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"date_interval": "day",
"metrics": ["average_position"],
"dimensions": ["date"],
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [2.5], "dimensions": ["2026-01-01"] },
{ "metrics": [2.3], "dimensions": ["2026-01-02"] },
{ "metrics": [2.1], "dimensions": ["2026-01-03"] },
{ "metrics": [2.0], "dimensions": ["2026-01-04"] },
{ "metrics": [2.2], "dimensions": ["2026-01-05"] },
{ "metrics": [2.4], "dimensions": ["2026-01-06"] },
{ "metrics": [2.2], "dimensions": ["2026-01-07"] }
]
}
```
**Use case:** Monitor daily ranking changes and identify trends.
Analyze visibility score and share of voice across different topics and prompt types for a specific company:
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["visibility_score", "share_of_voice"],
"dimensions": ["prompt", "topic"],
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [0.45, 0.88],
"dimensions": ["What is the best CRM software?", "CRM Software"]
},
{
"metrics": [0.38, 0.75],
"dimensions": ["Top project management tools for teams", "Project Management"]
},
{
"metrics": [0.30, 0.62],
"dimensions": ["Best enterprise collaboration platforms", "Collaboration"]
}
]
}
```
**Use case:** Analyze visibility score and share of voice across different topics and prompt types for a specific company.
Combine multiple tag groups to slice a category by intersecting independent dimensions
Each filter in the `filters` array narrows the result. To express **OR within a group**, list values in a single `in` filter. To express **AND across groups**, send multiple `in` filters on the same field.
```http theme={null}
POST /v1/reports/visibility HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["share_of_voice"],
"dimensions": ["asset_name"],
"filters": [
{
"field": "tag_id",
"operator": "in",
"value": [
"tag_id_product_a",
"tag_id_product_b",
"tag_id_product_c"
]
},
{
"field": "tag_id",
"operator": "in",
"value": ["tag_id_product_d"]
}
]
}
```
This matches prompts tagged with **at least one of** `product_a`, `product_b`, or `product_c` **and also** tagged `tag_id_product_d`. Equivalent boolean form: `(product_a OR product_b OR product_c) AND tag_id_product_d`.
A single `in` filter listing all four tag IDs would mean "any of these four":
`(product_a OR product_b OR product_c OR tag_id_product_d)`
## Sentiment Analysis
Analyze sentiment data and emotional responses across companies and topics. See the full [endpoint reference](/api-reference/reports/query-sentiment) for all available metrics, dimensions, and filters.
The same filter composition shown in [Mixed AND/OR Tag Filtering](#mixed-and%2For-tag-filtering) works on this endpoint.
Identify companies with the most positive sentiment:
```http theme={null}
POST /v1/reports/sentiment HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["positive"],
"dimensions": ["asset_name"],
"pagination": { "limit": 5 }
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [2413], "dimensions": ["Company A"] },
{ "metrics": [1856], "dimensions": ["Company B"] },
{ "metrics": [1204], "dimensions": ["Company C"] },
{ "metrics": [987], "dimensions": ["Company D"] },
{ "metrics": [714], "dimensions": ["Company E"] }
]
}
```
Sentiment metrics are integer counts, not percentages like visibility. `positive` = count of positive sentiment instances for that asset.
Available sentiment metrics: `positive`, `negative`, `occurrences` (total count).
**Use case:** Understand which companies have the best reputation and sentiment.
Analyze positive and negative sentiment across different themes for a specific company:
```http theme={null}
POST /v1/reports/sentiment HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"metrics": ["positive", "negative"],
"dimensions": ["theme"],
"pagination": {
"limit": 5
},
"filters": [
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"metrics": [12, 45],
"dimensions": ["Customer Support"]
},
{
"metrics": [8, 32],
"dimensions": ["Pricing"]
},
{
"metrics": [6, 28],
"dimensions": ["Ease of Use"]
},
{
"metrics": [4, 50],
"dimensions": ["Product Quality"]
},
{
"metrics": [2, 18],
"dimensions": ["Integration"]
}
]
}
```
**Use case:** Identify themes driving positive or negative sentiment for targeted improvements.
## Citation Reports
Track mentions, references, and citation patterns across domains and pages. See the full [endpoint reference](/api-reference/reports/query-citations) for all available metrics, dimensions, and filters.
The same filter composition shown in [Mixed AND/OR Tag Filtering](#mixed-and%2For-tag-filtering) works on this endpoint.
Track citation share by domain with daily granularity:
```http theme={null}
POST /v1/reports/citations HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-04-08",
"end_date": "2026-04-15",
"metrics": ["citation_share"],
"dimensions": ["date", "hostname"],
"date_interval": "day",
"order_by": { "date": "asc" }
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.092], "dimensions": ["2026-04-08 00:00:00", "example-a.com"] },
{ "metrics": [0.028], "dimensions": ["2026-04-08 00:00:00", "example-b.com"] },
{ "metrics": [0.021], "dimensions": ["2026-04-08 00:00:00", "example-c.com"] },
{ "metrics": [0.018], "dimensions": ["2026-04-08 00:00:00", "example-d.com"] },
{ "metrics": [0.015], "dimensions": ["2026-04-08 00:00:00", "example-e.com"] },
{ "metrics": [0.105], "dimensions": ["2026-04-09 00:00:00", "example-a.com"] },
{ "metrics": [0.030], "dimensions": ["2026-04-09 00:00:00", "example-b.com"] },
{ "metrics": [0.024], "dimensions": ["2026-04-09 00:00:00", "example-c.com"] },
{ "metrics": [0.019], "dimensions": ["2026-04-09 00:00:00", "example-d.com"] },
{ "metrics": [0.013], "dimensions": ["2026-04-09 00:00:00", "example-e.com"] },
{ "metrics": [0.088], "dimensions": ["2026-04-10 00:00:00", "example-a.com"] },
{ "metrics": [0.026], "dimensions": ["2026-04-10 00:00:00", "example-b.com"] }
]
}
```
**Use case:** Monitor how citation share trends over time across competing domains.
Get the top 5 domains ranked by citation share with total citation count:
```http theme={null}
POST /v1/reports/citations HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-04-08",
"end_date": "2026-04-15",
"metrics": ["citation_share", "count"],
"dimensions": ["hostname"],
"order_by": { "citation_share": "desc" },
"pagination": { "limit": 5 }
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.087, 358], "dimensions": ["example-a.com"] },
{ "metrics": [0.025, 102], "dimensions": ["example-b.com"] },
{ "metrics": [0.023, 95], "dimensions": ["example-c.com"] },
{ "metrics": [0.019, 78], "dimensions": ["example-d.com"] },
{ "metrics": [0.015, 61], "dimensions": ["example-e.com"] }
]
}
```
**Use case:** Identify the most cited domains in your category and their relative share.
Get citation share and count broken down by citation category:
```http theme={null}
POST /v1/reports/citations HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-04-08",
"end_date": "2026-04-15",
"metrics": ["citation_share", "count"],
"dimensions": ["citation_category"],
"order_by": { "citation_share": "desc" }
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.136, 542], "dimensions": ["Earned Media"] },
{ "metrics": [0.115, 458], "dimensions": ["Social"] },
{ "metrics": [0.079, 315], "dimensions": ["Owned"] },
{ "metrics": [0.053, 211], "dimensions": ["Competition"] },
{ "metrics": [0.034, 136], "dimensions": ["Blog"] },
{ "metrics": [0.028, 112], "dimensions": ["Partner"] },
{ "metrics": [0.024, 96], "dimensions": ["Distribution"] },
{ "metrics": [0.020, 80], "dimensions": ["Documentation"] },
{ "metrics": [0.016, 64], "dimensions": ["Press"] },
{ "metrics": [0.012, 48], "dimensions": ["Video"] },
{ "metrics": [0.010, 40], "dimensions": ["other"] }
]
}
```
**Use case:** Understand which citation categories drive the most mentions in your category.
Get the top 10 cited domains by citation share and count, grouped by citation category:
```http theme={null}
POST /v1/reports/citations HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-04-08",
"end_date": "2026-04-15",
"metrics": ["citation_share", "count"],
"dimensions": ["citation_category", "hostname"],
"order_by": { "citation_share": "desc" },
"pagination": { "limit": 10 }
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{ "metrics": [0.038, 152], "dimensions": ["Earned Media", "example-a.com"] },
{ "metrics": [0.035, 140], "dimensions": ["Social", "example-f.com"] },
{ "metrics": [0.028, 112], "dimensions": ["Earned Media", "example-b.com"] },
{ "metrics": [0.025, 100], "dimensions": ["Earned Media", "example-c.com"] },
{ "metrics": [0.024, 96], "dimensions": ["Social", "example-g.com"] },
{ "metrics": [0.021, 84], "dimensions": ["other", "example-d.com"] },
{ "metrics": [0.018, 72], "dimensions": ["Social", "example-h.com"] },
{ "metrics": [0.015, 60], "dimensions": ["Earned Media", "example-e.com"] }
]
}
```
**Use case:** Identify the top 10 most cited domains and which citation category they belong to.
## Raw Data Access
Access unprocessed prompt and answer data for custom analysis. See the full [endpoint reference](/api-reference/prompts/get-answers) for all available parameters and filters.
Get all visibility answers for a date range:
```http theme={null}
POST /v1/prompts/answers HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"filters": [
{
"field": "prompt_type",
"operator": "is",
"value": "visibility"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"created_at": "2026-01-01T08:15:00Z",
"prompt": "What are the best project management tools?",
"mentions": ["Company A", "Company B", "Company C"],
"prompt_type": "open-ended",
"response": "There are several leading project management tools available today. Company A offers comprehensive project tracking with built-in collaboration features...",
"citations": ["https://www.example.com/reviews", "https://www.example.com/best-tools"],
"themes": ["feature comparison", "pricing"],
"topic": "Project Management",
"region": "North America",
"model": "ChatGPT",
"model_id": "3f8a1b2c-1234-5678-abcd-ef0123456789",
"asset": "Company A"
},
...
]
}
```
**Use case:** Build custom dashboards and perform specialized analysis with raw answer data.
Get sentiment prompt answers filtered by a specific asset:
```http theme={null}
POST /v1/prompts/answers HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"category_id": "your_category_id",
"start_date": "2026-01-01",
"end_date": "2026-01-07",
"filters": [
{
"field": "prompt_type",
"operator": "is",
"value": "sentiment"
},
{
"field": "asset_name",
"operator": "is",
"value": "your_company_name"
}
]
}
```
```json theme={null}
{
"info": {}, // removed for brevity
"data": [
{
"created_at": "2026-01-02T11:30:00Z",
"prompt": "What do users think about Company A's analytics features?",
"mentions": ["Company A"],
"prompt_type": "brand-direct",
"response": "Users generally have positive feedback about Company A's analytics capabilities. The platform is praised for its comprehensive dashboard and intuitive reporting features...",
"citations": ["https://www.example.com/review/company-a"],
"themes": ["analytics quality", "ease of use"],
"topic": "Product Feedback",
"region": "Europe",
"model": "Perplexity",
"model_id": "c4d5e6f7-3456-7890-cdef-012345678901",
"asset": "Company A"
},
...
]
}
```
**Use case:** Analyze raw sentiment responses for a specific brand across models and regions.
# Example Requests
Source: https://docs.tryprofound.com/rest-api/examples/example
Sample API requests and responses to help you get started
Sample requests for Answer Engine Insights endpoints.
Sample requests for Agent Analytics endpoints.
Sample requests for Agent endpoints.
Sample requests for OpenAI Ads Partner API endpoints.
# Knowledge Bases
Source: https://docs.tryprofound.com/rest-api/examples/knowledge-bases
Sync documents into a Profound knowledge base and search them.
This guide shows how to sync documents from an external system such as Guru into a Profound knowledge base. All examples require authentication with an API key.
Knowledge bases must be created in the Profound app. The API cannot create a knowledge base. Replace `your_api_key`, `your_knowledge_base_id`, and `your_organization_id` with your actual values.
## Syncing documents walkthrough
Use this flow to mirror documents and folders from an external system:
1. Use [**List Knowledge Bases**](/api-reference/knowledge-bases/list-knowledge-bases) to find the knowledge base ID.
2. Use [**Add Folder**](/api-reference/knowledge-bases/add-folder) to mirror source folders when needed.
3. Use [**Add Document**](/api-reference/knowledge-bases/add-document) to upload each source document.
4. Use [**Update Document**](/api-reference/knowledge-bases/update-document) for idempotent re-syncs.
5. Use [**Delete Document**](/api-reference/knowledge-bases/delete-document) or [**Delete Folder**](/api-reference/knowledge-bases/delete-folder) when content is removed from the source system.
### 1. List Knowledge Bases
First, get the ID of the knowledge base you want to sync. The `id` returned here is required as the `knowledge_base_id` path parameter for every other Knowledge Base request.
```http theme={null}
GET /v1/knowledge-bases HTTP/1.1
X-API-Key: your_api_key
```
```json theme={null}
{
"data": [
{
"id": "your_knowledge_base_id",
"name": "Product Documentation",
"slug": "product-documentation",
"description": "Product guides and reference material",
"created_at": "2026-04-24T19:03:15.459951Z"
}
],
"pagination": {}
}
```
If your API key can access multiple organizations, pass `organization_id` on the request:
```http theme={null}
GET /v1/knowledge-bases?organization_id=your_organization_id HTTP/1.1
X-API-Key: your_api_key
```
Use the same query parameter on subsequent requests when the API key spans multiple organizations.
### 2. Add a Folder
Folders are empty when created. A document's folder must already exist, so create the source hierarchy before uploading documents, and use folder paths such as `Engineering/API` to mirror the hierarchy in Guru. Create parent folders before their nested folders. Creating a folder that already exists returns `409 Conflict`.
```http theme={null}
POST /v1/knowledge-bases/your_knowledge_base_id/folders HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"path": "Engineering"
}
```
```json theme={null}
{
"message": "Folder added.",
"path": "Engineering"
}
```
### 3. Add a Document
Add a document as JSON by sending its text in the `text` field. `folder` is optional; when provided, it is the folder path containing the document.
```http theme={null}
POST /v1/knowledge-bases/your_knowledge_base_id/documents HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"name": "authentication.md",
"folder": "Engineering",
"text": "# Authentication\n\nUse an API key to authenticate requests."
}
```
You can also upload a file as multipart form data. This is useful when your source system provides document files directly:
```bash theme={null}
curl -X POST "https://api.tryprofound.com/v1/knowledge-bases/your_knowledge_base_id/documents" \
-H "X-API-Key: your_api_key" \
-F "name=authentication.md" \
-F "folder=Engineering" \
-F "file=@./authentication.md"
```
Both forms return the document name, path, and folder:
```json theme={null}
{
"message": "Document added.",
"name": "authentication.md",
"path": "Engineering/authentication.md",
"folder": "Engineering"
}
```
Adding a document does not overwrite an existing document: if the document path already exists, the request returns `409 Conflict`. Use update instead when the path already exists.
### 4. Update a Document
Update overwrites an existing document at the target path. The JSON request has the same `name`, `text`, and optional `folder` fields as add:
```http theme={null}
PUT /v1/knowledge-bases/your_knowledge_base_id/documents HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"name": "authentication.md",
"folder": "Engineering",
"text": "# Authentication\n\nUse the latest API key instructions."
}
```
Multipart uploads use the same `name` and optional `folder` fields, with `file` replacing `text`:
```bash theme={null}
curl -X PUT "https://api.tryprofound.com/v1/knowledge-bases/your_knowledge_base_id/documents" \
-H "X-API-Key: your_api_key" \
-F "name=authentication.md" \
-F "folder=Engineering" \
-F "file=@./authentication.md"
```
Update targets an existing document path in an existing folder; a missing folder returns `404 Not Found`.
### 5. Delete a Document
Delete a document by sending its name in a JSON request body. Include `folder` in the name when deleting a nested document:
```http theme={null}
DELETE /v1/knowledge-bases/your_knowledge_base_id/documents HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"name": "Engineering/authentication.md"
}
```
### 6. Delete a Folder
Delete an empty folder by setting `recursive` to `false` (the default):
```http theme={null}
DELETE /v1/knowledge-bases/your_knowledge_base_id/folders HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"path": "Engineering",
"recursive": false
}
```
If the folder is not empty, the request returns `409 Conflict` and nothing is deleted. To delete the folder and all of its contents, set `recursive` to `true`:
```json theme={null}
{
"path": "Engineering",
"recursive": true
}
```
### 7. Search a Knowledge Base
Search with a required `query` and `top_k` between 1 and 100. Set `return_full_page` to `true` to request full page content instead of snippets.
```http theme={null}
POST /v1/knowledge-bases/your_knowledge_base_id/search HTTP/1.1
Content-Type: application/json
X-API-Key: your_api_key
{
"query": "How do I authenticate?",
"top_k": 5,
"return_full_page": false,
"filters": {
"tags": ["api"],
"folders": ["Engineering"]
}
}
```
`filters.tags` matches documents with any of the supplied tags. `filters.folders` limits the search to folder paths and currently accepts exactly one folder.
Each result includes an `id`, relevance `score`, `metadata`, and matched `content`:
```json theme={null}
{
"data": [
{
"id": "Engineering/authentication.md",
"score": 0.94,
"metadata": {
"folder_path": "Engineering",
"source_filename": "authentication.md"
},
"content": "Use an API key to authenticate requests."
}
],
"pagination": {}
}
```
For an external-system sync, loop over the source documents, use their folder paths to mirror the source hierarchy, use `PUT` for idempotent re-syncs, and use `DELETE` for documents removed from the source.
# OpenAI Ads
Source: https://docs.tryprofound.com/rest-api/examples/openai-ads
Sample requests for OpenAI Ads Partner API endpoints
This guide provides examples of common API requests. All examples require authentication via API key.
Replace `` with your actual Profound API key value. Learn how to generate it in [Authentication](/rest-api/authentication).
## Examples
### Get campaign insights for a date range
```bash theme={null}
curl -G "https://api.tryprofound.com/v1/ads/openai-ads/ad-account/insights" \
-H "X-API-Key: your_api_key" \
-d "aggregation_level=campaign" \
--data-urlencode 'time_ranges[]={"type":"date_range","since":"2026-07-01","until":"2026-07-18"}'
```
### Get daily campaign insights
```bash theme={null}
curl -G "https://api.tryprofound.com/v1/ads/openai-ads/ad-account/insights" \
-H "X-API-Key: your_api_key" \
-d "aggregation_level=campaign" \
-d "time_granularity=daily" \
--data-urlencode 'time_ranges[]={"type":"date_range","since":"2026-07-01","until":"2026-07-18"}'
```
# Releases
Source: https://docs.tryprofound.com/rest-api/integrations/tableau/releases
Download the latest version of Tableau (WDC 3.0) for data import
* Fixes for large responses
[Download](https://static.tryprofound.com/integrations/tableau/profound-connector-1.1.0.taco)
* Initial release of Tableau (WDC 3.0) for data import
[Download](https://static.tryprofound.com/integrations/tableau/profound-connector-1.0.0.taco)
# Usage
Source: https://docs.tryprofound.com/rest-api/integrations/tableau/usage
Import data into Tableau using Web Data Connector 3.0
## System Requirements
**Minimum required version**
* Tableau Desktop 2023.3 or higher
### Compatible Operating Systems
* Windows 10 or higher
* macOS 12 (Monterey) or higher
## Download
The connector is available on our [releases page](/rest-api/integrations/tableau/releases). Download the latest version of `profound-connector.taco` from there.
## Installation
### Windows Installation
1. **Locate the Tableau connectors directory**
Open Windows Explorer and navigate to:
```
C:\Users\[YourUsername]\Documents\My Tableau Repository\Connectors
```
If the `Connectors` folder doesn't exist, create it manually
2. **Copy the .taco file**
* Copy the downloaded `profound-connector.taco` file
* Paste it into the Connectors folder
* **Important**: Do not unzip the .taco file
3. **Restart Tableau Desktop**
* Completely close Tableau Desktop if it's open
* Reopen the application
4. **Verify the installation**
* The connector will appear as "AEO Connector by Profound" in the connectors list
### macOS Installation
1. **Locate the Tableau connectors directory**
* Open Finder
* Press `Cmd + Shift + G`
* Enter the following path:
```
~/Documents/My Tableau Repository/Connectors
```
If the `Connectors` folder doesn't exist, create it
2. **Copy the .taco file**
* Drag the `profound-connector.taco` file to the Connectors folder
* **Important**: The file must keep the .taco extension
3. **Restart Tableau Desktop**
* Completely close Tableau Desktop if it's open
* Reopen the application
4. **Verify the installation**
* The connector will appear as "AEO Connector by Profound" in the connectors list
## First Connection
Launch Tableau Desktop 2023.3 or higher
1. On the start page, click **"More..."** in the left panel under "To a Server"
2. Look for **"AEO Connector by Profound"** in the list
3. Click to select it
The connector UI will open with an API Key field:
* Enter your **API Key** generated from the platform
* Click **"Access"** to proceed
Once authenticated, you can choose between:
* **Raw Answer**: Access raw data with custom filtering options
* **Report Types**: Select from available pre-configured aggregated reports
Select your preferred data source and apply any filters as needed
Click **"Import to Tableau"** to load the selected data into Tableau
## Troubleshooting
### The connector doesn't appear in Tableau
* Go to **Help → About Tableau**
* Confirm you have version 2023.3 or higher
**Windows:**
* Confirm the file is in `C:\Users\[YourUsername]\Documents\My Tableau Repository\Connectors`
**macOS:**
* Confirm the file is in `~/Documents/My Tableau Repository/Connectors`
Make sure to close all Tableau Desktop windows before reopening
### Connection Errors
* Verify you've copied the complete API Key without spaces
* Check that your API Key is active
* Generate a new API Key if necessary
* Verify the selected endpoint contains data for your filters
* Check date ranges aren’t too restrictive
* Confirm API key has access to the requested data
## Updating the Connector
When a new version is available:
1. Download the new version of the .taco file from the releases page
2. Delete the old file from the Connectors folder
3. Copy the new .taco file
4. Restart Tableau Desktop
## Frequently Asked Questions
[Here you can refer to the API Key generation documentation](/rest-api/authentication)
The version is included in the .taco filename you downloaded.
# WDC 2.0
Source: https://docs.tryprofound.com/rest-api/integrations/tableau/wdc-2
Import data into Tableau using Web Data Connector 2.0
[https://tableau.tryprofound.com/](https://tableau.tryprofound.com/)
## Requirements
Valid API key with permissions to access desired endpoints
Stable connection to access the export tool
## How to Use
Launch Tableau Desktop (version 10.4 or higher required)
Select **More** on the left side of the screen and search for **Web Data Connector**:
Enter the tool URL: `https://tableau.tryprofound.com/`
Looking for your API key? [Click here](/rest-api/authentication#getting-your-api-key)
Enter your API key when prompted. Select **Access** when ready:
Select the desired data and configure any additional filters:
Click **Import to Tableau** to import data directly into your Tableau workspace
It may take a few minutes to populate the data into Tableau.
## Available Data Sources
The tool supports both processed reports and raw data endpoints
* **Report Endpoints**: Pre-processed analytics and summary data
* **Raw Data**: Unprocessed data directly from database
## Troubleshooting
Ensure your API key has the correct permissions for the selected endpoint
**Solutions:**
* Verify API key is correct and active
**Solutions:**
* Verify the selected endpoint contains data for your filters
* Check date ranges aren't too restrictive
* Confirm API key has access to the requested data
**Solutions:**
* Try reducing the data range
* Use more specific filters to limit data volume
* Contact support if large exports are needed regularly
Tableau integration uses WDC 2.0, which works with most Tableau Desktop versions
**Solutions:**
* Ensure Tableau Desktop 10.4 or higher
* Check firewall settings allow WDC connections
* Verify the tool URL is correctly entered in Tableau
## Technical Notes
Tableau integration uses Web Data Connector 2.0, which is a legacy but stable technology supported by Tableau
* **Data Types**: Automatic detection and formatting for dates, numbers, and text
* **File Size**: Large exports may take additional time to process
* **Refresh**: Tableau connections can be refreshed to get updated data
## Need Help?
If you encounter issues or need to request API access, contact our [support team](mailto:support@tryprofound.com) for assistance.
# Introduction
Source: https://docs.tryprofound.com/rest-api/introduction
An overview of the REST API and its capabilities
This feature is only available upon request. To request access, please contact [support](mailto:support@tryprofound.com).
If you already have access, view the [documentation](/rest-api/authentication) to learn how to manage your API keys.
## Overview
Our API allows developers to interact with the data displayed on our platform programmatically. All API responses are returned in JSON format, making it easy to integrate with modern applications and tools.
### Base URL
All API requests should be made to:
```
https://api.tryprofound.com
```
**Key capabilities:**
* Automate data retrieval and processing tasks
* Create integrations with third-party applications
* Generate custom reports and analytics
* Access processed reports and raw per-execution prompt-answer data
## API Features
### Report Generation
Create comprehensive reports with processed data from our prompt system. Compare performance metrics across different companies, time periods, or evaluation criteria to gain insights into your data.
### Raw Per-Execution Data
Access raw per-execution prompt-answer rows through
`POST /v2/prompts/answers`, including model responses, mentions, citations,
and search queries.
### Organization-Scoped Data
Each API key provides access to data belonging to its associated organization, ensuring proper data isolation and security.
## Getting Started
To begin using the API, you'll need an API key from your user profile on our platform. This key authenticates your requests and grants access to your organization's data.
For authentication details and request examples, see:
* [Authentication](/rest-api/authentication) - How to authenticate your requests
* [Date Ranges & Timezones](/rest-api/date-ranges) - Understanding date parameters and timezone handling
* [Example Requests](/rest-api/examples) - Sample API calls and responses
* [Answer Engine Insights](/rest-api/examples/answer-engine-insights)
* [Agent Analytics](/rest-api/examples/agent-analytics)
* [Agents](/rest-api/examples/agents)
## API Fundamentals
### Data Organization
Each organization has access to specific categories and datasets. Use the `/v1/org` endpoints to:
* Discover available data categories
* Obtain identifiers for filtering
* Understand your data scope and permissions
### Required Parameters
Answer Engine Insights reports require a **category identifier** and
**date range parameters** (`start_date` and `end_date`). Traffic reports
for bots and referrals are domain-scoped instead. See [Date Ranges &
Timezones](/rest-api/date-ranges) for proper formatting.
### API Versioning
The API currently has both `v1` and `v2` endpoints:
* `v1` endpoints remain active, including the existing V1 report endpoints
* `v2` now spans Answer Engine Insights reports under
`/v2/reports/visibility`, `/v2/reports/citations`,
`/v2/reports/sentiment`, `/v2/reports/query-fanouts`,
`/v2/reports/factcheck`, and `/v2/reports/factcheck/claims`, as well as
`/v2/prompts/answers`. Each has a `/stream` SSE variant.
Versioned paths ensure compatibility as the API evolves.
## Rate Limits
**Default limits:** 600 requests per hour per API key.
### Rate Limit Headers
Every API response includes these headers:
* `X-RateLimit-Limit`: Your total request limit
* `X-RateLimit-Remaining`: Remaining requests in current period
* `X-RateLimit-Reset`: When the limit resets (Unix timestamp)
### Handling Rate Limits
When you exceed the limit, you'll receive a `429 Too Many Requests` error. The response includes a `Retry-After` header indicating how long to wait before retrying.
Need higher limits? Contact our support team to discuss your requirements.
## Response Format
All API responses use JSON format with consistent structure for errors and successful responses.
# Get Answers
Source: https://docs.tryprofound.com/rest-api/reports/query-answers-v2
POST /v2/prompts/answers
The raw per-execution rows behind every report: one row per model response,
with its mentions, citations, and search queries. No aggregation.
* **No `group_by` / `sort`:** rows are newest-first by date.
* **`include`** picks which fields to return (`response`, `mentions`, `citations`, `search_queries`, …); omit it for all.
* `mentions` is a flat, deduped list in the order entities appear in the response.
* **Filters:** prompt-level fields plus `analysis_type` (prompt-level: `visibility`·`sentiment`·`factcheck`), and top-level `domain`/`page` leaves: `is` one value or `in` a list (exact cited-URL match).
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared request shape, filter tree, grouping, and pagination.
`POST /v2/prompts/answers/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"date": "2026-06-19", "model": {"name": "ChatGPT"}, "prompt": "", "mentions": ["Profound", ""], "citations": ["https://example.com/article"]}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/prompts/answers \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-18",
"end_date": "2026-06-19",
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 27690,
"count": 10,
"next_cursor": "Z0FBQUFBQnFQcjNsbDZZaWlzZjR2cXJt...",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"include": [
"run_id", "date", "model", "topic", "topic_id", "persona", "region",
"tags", "prompt", "prompt_id", "response", "mentions", "citations",
"search_queries", "analysis_types"
],
"start_date": "2026-06-18",
"end_date": "2026-06-19",
"filter": null
},
"data": [
{
"run_id": "",
"date": "2026-06-19",
"model": { "id": "", "name": "ChatGPT" },
"topic": "",
"topic_id": "",
"region": "United States",
"persona": null,
"tags": [],
"prompt": "",
"prompt_id": "",
"response": "",
"mentions": ["Profound", ""],
"citations": ["https://example.com/article"],
"search_queries": [""],
"analysis_types": ["visibility"]
}
// ...9 more rows (count: 10, total_results: 27690); paginate with next_cursor
]
}
```
# Citations
Source: https://docs.tryprofound.com/rest-api/reports/query-citations-v2
POST /v2/reports/citations
Which domains and pages AI answers cite, ranked most-cited first. Group by
`page` for URL-level rows; use `scope: "owned"` to see only domains you own.
* **Metrics:** `count` (raw citations), `citation_share` (per-model average share), `rank`, `first_cited_at` (pages only).
* **`group_by`:** `page`, `date`, `model`, `topic`, `region`, `persona`, `prompt`.
* **No `sort`:** rows are always ranked most-cited first.
* **Citation-layer filters:** `domain` (subdomain-aware), `page`, `analysis_type` (`visibility`·`sentiment`·`factcheck`·`all`), `citation_category` (`owned`·`competition`·`social`·`earned_media`·`earned_institutions`·`pr_wire`·`other`·custom), `citation_tag` (your custom tags — list them with [Get Citation Tags](/api-reference/organization/get-category-citation-tags)).
`citation_category` and `citation_tag` are both top-level `and` leaves
accepting `is` / `in`; values in one `in` are OR'd, so
`{"field": "citation_tag", "op": "in", "value": ["Editorial", "Docs"]}`
matches URLs carrying either tag.
`count` and `citation_share` measure different things: `citation_share` is
averaged per AI model, so it won't sort in lockstep with raw `count`.
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared request shape, filter tree, grouping, and pagination.
`POST /v2/reports/citations/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"domain": "reddit.com", "rank": 1, "count": 13940, "citation_share": 0.040}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/citations \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15"
}'
```
```bash cURL (filter by citation tag) theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/citations \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": {
"field": "citation_tag",
"op": "in",
"value": ["Editorial", "Docs"]
}
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 11662,
"count": 10,
"next_cursor": "Z0FBQUFBQnFQcWdrbDRiSHpGaktVNm5N...",
"scope": "all",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"metrics": ["count", "citation_share", "rank"],
"analysis_types": ["visibility"],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": null
},
"data": [
{ "domain": "reddit.com", "rank": 1, "count": 13940, "citation_share": 0.040 },
{ "domain": "youtube.com", "rank": 2, "count": 16287, "citation_share": 0.037 },
{ "domain": "tryprofound.com", "rank": 3, "count": 10414, "citation_share": 0.029 }
// ...7 more rows in this page (count: 10, total_results: 11662); paginate with next_cursor
]
}
```
# FactCheck Claims
Source: https://docs.tryprofound.com/rest-api/reports/query-factcheck-claims-v2
POST /v2/reports/factcheck/claims
The inaccurate claims behind your accuracy score — the false statements AI
answers made about your category, from the platform's FactCheck tab. Returns a
flat, paginated list, or `group_by` one dimension to section them. A claim is
`{ cluster_id, claim, occurrence }` plus whatever `include` adds.
* **`occurrence`:** the % of scoped responses that carry the claim.
* **`include`:** any of `theme`, `reasoning`, `models`, `evidence`, `citation_sources`.
* `models[]` — which models make the claim: `{ id, name, occurrence }`.
* `evidence[]` — refuting knowledge-base snippets: `{ id, kb_path, kb_snippet, source_updated_at }`.
* `citation_sources[]` — the cited pages driving the claim: `{ href, hostname, citation_category, domain_category, snippet, citation_share }`. `citation_share` is a percentage, model-balanced, matching the Citations tab.
* **`group_by`:** 0 or 1 of `model`, `region`, `persona`, `prompt`, `topic`, `tag`, `theme` (no `citation` or `date` — those are scores dimensions). Empty → one flat paginated list; a dimension → one section per value: `{ : { id, name }, accuracy, accurate, inaccurate, total_claims, claims: […] }`, each carrying **all** its claims.
* **`filter`:** the same constrained tree as [scores](/rest-api/reports/query-factcheck-v2) — a top-level `and` of single-field leaves over `model`/`topic`/`region`/`persona`/`prompt`/`tag` (only `topic` negatable).
A few guardrails return `422` (with a message): `citation_sources` isn't available with `group_by` (its share is scope-sensitive) — request it on the flat list; `group_by: ["tag"]` can't be combined with a `tag` filter (tags are multi-valued, so co-tag sections would escape the filter); and sectioning by `model` over an unusually large scope (>\~2000 inaccurate clusters) — narrow the range or `filter`.
`POST /v2/reports/factcheck/claims/stream` takes the **same request body**
and returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per claim.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
The stream is the **flat list only** — `group_by` and the per-claim
`evidence`/`citation_sources` lookups return `422`; use the non-stream
endpoint for sectioned or enriched claims.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per claim, same shape as data[] above
data: {"cluster_id": "7a5…", "claim": "Profound covers more than 10 AI engines.", "occurrence": 6.6}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/factcheck/claims \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"include": ["reasoning", "citation_sources"]
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 41,
"count": 25,
"next_cursor": "eyJ…",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"group_by": [],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": null,
"include": ["reasoning", "citation_sources"]
},
"data": [
{
"cluster_id": "7a576…",
"claim": "Profound covers more than 10 AI engines.",
"occurrence": 6.6,
"reasoning": "Conflates GEO tooling with the engines Profound actually tracks.",
"citation_sources": [
{
"href": "tryprofound.com/blog/best-geo-tools",
"hostname": "tryprofound.com",
"citation_category": "owned",
"domain_category": "owned",
"snippet": "Profound tracks ten answer engines…",
"citation_share": 14.2
}
]
}
]
}
```
# FactCheck
Source: https://docs.tryprofound.com/rest-api/reports/query-factcheck-v2
POST /v2/reports/factcheck
Accuracy scores for your category's fact-checked claims — the numbers behind
the platform's FactCheck (Accuracy) tab. `group_by` picks the slice; `accuracy`
is a ratio `0`–`1` (`accurate / (accurate + inaccurate)`). Per-category, so there
is no `asset` or `scope`.
* **Metrics (every row):** `accuracy` (`0`–`1`), `accurate`, `inaccurate`.
* **`group_by`:** 0–2 of `date`, `model`, `region`, `persona`, `prompt`, `topic`, `tag`, `theme` — **or one `citation`** (citation can't be combined with another dimension). Empty → one headline score; `["date"]` → the daily accuracy series; two dims (e.g. `["model", "date"]`) → one row per combination, in a single query.
* **Row shape follows `group_by`:** a value dimension → `{ : { id, name }, … }`; `["citation"]` → `{ citation: { url, citation_category }, … }` (a citation is a URL, not an id/name); `["date"]` → `{ date, … }`.
* **`filter`:** scopes which responses are counted — a top-level `and` of single-field leaves over `model`, `topic`, `region`, `persona`, `prompt`, `tag`. One leaf per field (use `in` for OR within a field); only `topic` may be negated. This is a **narrower** grammar than the other v2 reports (no `or`/`not` nesting).
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared `{ info, data }` shape, grouping, and pagination. FactCheck uses that envelope but has no `scope`/`assets`/`metrics` params and a constrained `filter` (above). For the inaccurate claims themselves, see [FactCheck Claims](/rest-api/reports/query-factcheck-claims-v2).
`POST /v2/reports/factcheck/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"model": {"id": "a1c9…", "name": "ChatGPT"}, "accuracy": 0.986, "accurate": 1980, "inaccurate": 28}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/factcheck \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"group_by": ["model"]
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 9,
"count": 9,
"next_cursor": null,
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"group_by": ["model"],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": null
},
"data": [
{ "model": { "id": "a1c9…", "name": "ChatGPT" }, "accuracy": 0.986, "accurate": 1980, "inaccurate": 28 },
{ "model": { "id": "b7f2…", "name": "Microsoft Copilot" }, "accuracy": 0.831, "accurate": 1360, "inaccurate": 276 }
]
}
```
# Query Fanouts
Source: https://docs.tryprofound.com/rest-api/reports/query-fanouts-v2
POST /v2/reports/query-fanouts
The search queries an AI generates behind the scenes when answering a prompt.
**Coverage is partial:** metrics cover only runs that emitted fanout data (see
`info.coverage_note`).
* **Metrics:** `total_fanouts` (query count), `fanouts_per_execution` (avg queries per execution), `query_variations` (distinct fanout queries), `share`.
* **`group_by`:** `prompt` (default), `query`, `model`, `region`, `date`.
* `query` requires `prompt` in `group_by`; `share` requires `query`; `query_variations` can't be combined with `query`.
* **`analysis_type`** filter defaults to `visibility`.
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared request shape, filter tree, grouping, and pagination.
`POST /v2/reports/query-fanouts/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"prompt": "AI search optimization startups...", "rank": 1, "total_fanouts": 190, "fanouts_per_execution": 3.0, "query_variations": 143}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/query-fanouts \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15"
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 322,
"count": 10,
"next_cursor": "Z0FBQUFBQnFQcVJ3R1RlcGtXc0g5eTZT...",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"metrics": ["total_fanouts", "fanouts_per_execution", "query_variations"],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"coverage_note": "Fanout metrics cover only runs that emitted query-fanout data.",
"filter": null
},
"data": [
{ "prompt": "AI search optimization startups...", "rank": 1, "total_fanouts": 190, "fanouts_per_execution": 3.0, "query_variations": 143 },
{ "prompt": "Best AI visibility products...", "rank": 2, "total_fanouts": 168, "fanouts_per_execution": 2.7, "query_variations": 143 }
// ...8 more rows in this page (count: 10, total_results: 322); paginate with next_cursor
]
}
```
# Sentiment
Source: https://docs.tryprofound.com/rest-api/reports/query-sentiment-v2
POST /v2/reports/sentiment
Per-brand sentiment as positive/negative percentages (0–100). `asset` is
**required** (sentiment is per-brand). Add `comparison_start_date` /
`comparison_end_date` to get a `previous` block on each row for
period-over-period deltas in a single call.
* **Metrics:** `positive_sentiment`, `negative_sentiment` (sum to 100 per row), and `occurrence` (opt-in; needs `theme`/`claim` grouping or filtering).
* **`group_by`:** up to two of `topic`, `region`, `model`, `prompt`, `persona`, `tag`, `theme`, `claim`, `run`, `competitor` (plus `date`).
* **Entity filters:** `theme` / `claim` accept `is`/`in`, single value, name or id.
* `include_cited_websites: true` adds `cited_websites` per row (with `theme`/`claim` grouping).
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared request shape, filter tree, grouping, and pagination.
`POST /v2/reports/sentiment/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"theme": {"id": "a14e0c2d", "name": "Analytics"}, "rank": 1, "positive_sentiment": 95.4, "negative_sentiment": 4.6}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/sentiment \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"asset": "Profound",
"start_date": "2026-06-09",
"end_date": "2026-06-15"
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 1,
"count": 1,
"next_cursor": null,
"asset": "Profound",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"metrics": ["positive_sentiment", "negative_sentiment"],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": null
},
"data": [
{
"positive_sentiment": 79.1,
"negative_sentiment": 20.9
}
]
}
```
# Brands
Source: https://docs.tryprofound.com/rest-api/reports/query-shopping-brands-v2
POST /v2/reports/shopping/brands
This report shows brand visibility in ChatGPT shopping results. It gives how
often each brand appears, its average position, and its rank. Select the brands
with `assets`. Divide the results with `group_by`. Each metric is a named field
on the row.
* **Metrics:** `visibility_score` (the share of shopping results that include the brand); `average_position` (the average rank when the brand appears — a **lower** number is **better**); `visibility_rank`.
* **`group_by`:** `date`, `topic`, `region`, or `prompt`.
* **Brand selection:** Select the brands with the `assets` parameter. Give one name or a list. `scope: "all"` ranks all brands. `scope: "owned"` (the default) returns only your brands. An `assets` selection returns one page and ignores `limit`.
* **Filter fields:** `topic`, `region`, `persona`, `prompt`, `tag`.
Shopping data comes from ChatGPT only. No shopping report has a `model`
group\_by or a `model` filter.
The v2 reports share one request shape. For the filter tree, grouping, and
pagination, see [Filtering & concepts](/rest-api/reports/reports-v2-overview).
`POST /v2/reports/shopping/brands/stream` uses the **same request body**. It
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event for each row.
The stream rejects `limit` and `cursor`. It returns all rows by default. To
set a maximum, use `max_results` (maximum 50000). Use the stream to get a
large result in one request.
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/shopping/brands \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"group_by": ["date"],
"metrics": ["visibility_score", "average_position", "visibility_rank"],
"scope": "owned",
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 1,
"count": 1,
"next_cursor": null,
"scope": "owned",
"assets": null,
"models": ["ChatGPT"],
"metrics": ["visibility_score", "average_position", "visibility_rank"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": null
},
"data": [
{
"asset": { "name": "Example Brand", "owned": true },
"date": "2026-06-01",
"visibility_score": 0.42,
"average_position": 3.2,
"visibility_rank": 1
}
]
}
```
# Merchants
Source: https://docs.tryprofound.com/rest-api/reports/query-shopping-merchants-v2
POST /v2/reports/shopping/merchants
This report gives merchant data for ChatGPT shopping results. `group_by`
selects one of three views. `merchant_share` is the merchant's share of offers.
`merchant_visibility` is the merchant's share of the runs it appears in. These
are two different measures.
### Views
* **Distribution** (omit `group_by`) — one row for each merchant. Metrics: `merchant_share`, `merchant_share_rank`, `merchant_visibility`, `merchant_visibility_rank`. To get a time series, add `date`.
* **Brand share** (`group_by: ["brand"]`) — one row for each merchant and brand. Metrics: `merchant_share`, `brand_share` (the brand's share in the merchant), `visibility_rank`.
* **Top products** (`group_by: ["product"]`) — one row for each merchant and product. Metrics: `merchant_visibility`, `product_visibility`, `product_rank`.
**Filter fields:** `topic`, `region`, `persona`, `prompt`, `tag`. The
distribution view also accepts a `brand` filter.
### Rules
* Use the metrics that are valid for the view. Other metrics return `422`.
* Group by `brand` **or** `product`. Do not use both.
* `date` is available in the distribution view only. `group_by: ["brand", "date"]` or `["product", "date"]` returns `422`.
* The `brand` filter is available in the distribution view only.
In the distribution view, `merchant_visibility` and `merchant_visibility_rank`
are run-appearance metrics. The report gets them from a second query and adds
them to each merchant. Request them only when you need them.
Shopping data comes from ChatGPT only. No shopping report has a `model`
group\_by or a `model` filter.
The v2 reports share one request shape. For the filter tree, grouping, and
pagination, see [Filtering & concepts](/rest-api/reports/reports-v2-overview).
`POST /v2/reports/shopping/merchants/stream` uses the **same request body**.
It returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event for each row.
The stream rejects `limit` and `cursor`. It returns all rows by default. To
set a maximum, use `max_results` (maximum 50000).
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/shopping/merchants \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"metrics": ["merchant_share", "merchant_share_rank", "merchant_visibility", "merchant_visibility_rank"],
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 24,
"count": 10,
"next_cursor": "eyJvZmZzZXQiOjEwfQ==",
"view": "distribution",
"models": ["ChatGPT"],
"metrics": ["merchant_share", "merchant_share_rank", "merchant_visibility", "merchant_visibility_rank"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": null
},
"data": [
{
"merchant_name": "Example Retailer",
"merchant_share": 0.25,
"merchant_share_rank": 1,
"merchant_visibility": 0.40,
"merchant_visibility_rank": 1
}
]
}
```
# Products
Source: https://docs.tryprofound.com/rest-api/reports/query-shopping-products-v2
POST /v2/reports/shopping/products
This report shows product visibility in ChatGPT shopping results. It can also
give the merchant offers for each product. The report returns each product as
`{ name, brand }` with its metrics as named fields.
* **Metrics:** `visibility_score`; `average_position` (a **lower** number is **better**); `visibility_rank`; the position-frequency metrics `position1_percentage`, `position2_percentage`, `position3_percentage`, `position_above3_percentage`; `product_rating`; `product_num_reviews`.
* **Position-frequency metrics:** Each one is the share of the product's appearances at that slot (`position1` = top; `position_above3` = below rank 3). The values are **0–1 fractions**, not 0–100. The four values sum to about 1.
* **`group_by`:** `date`, `topic`, or `prompt`.
* **Filter fields:** `topic`, `region`, `persona`, `prompt`, `tag`, `brand`, `merchant`.
### Merchant offers
To attach the merchant offers to each product, set `include_merchants: true`.
The report then adds `merchants` (a list of `{ name, price }`), `product_url`,
and `product_image_urls`. This mode does not accept `group_by` or
`target_product`. The position-frequency metrics are not available in this mode.
### Competitor mode
To return one product and its top competitors, set `target_product` to a
product name. To set the number of competitors, use `competitor_limit` (the
default is 5). Competitor mode is available in the item view only. Do not use it
with `include_merchants`.
Shopping data comes from ChatGPT only. No shopping report has a `model`
group\_by or a `model` filter.
The v2 reports share one request shape. For the filter tree, grouping, and
pagination, see [Filtering & concepts](/rest-api/reports/reports-v2-overview).
`POST /v2/reports/shopping/products/stream` uses the **same request body**.
It returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event for each row.
The stream rejects `limit` and `cursor`. It returns all rows by default. To
set a maximum, use `max_results` (maximum 50000).
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/shopping/products \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"include_merchants": true,
"metrics": ["visibility_score", "product_rating", "product_num_reviews"],
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 128,
"count": 10,
"next_cursor": "eyJvZmZzZXQiOjEwfQ==",
"models": ["ChatGPT"],
"include_merchants": true,
"metrics": ["visibility_score", "product_rating", "product_num_reviews"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": null
},
"data": [
{
"product": { "name": "Example Running Shoe", "brand": "Example Brand" },
"merchants": [
{ "name": "Example Retailer", "price": "$120.00" },
{ "name": "Example Brand", "price": "$110.00" }
],
"product_url": "https://www.example.com/p/example-running-shoe",
"product_image_urls": ["https://images.example.com/products/example-running-shoe.jpg"],
"product_rating": 4.5,
"product_num_reviews": 1200,
"visibility_score": 0.30
}
]
}
```
# Trigger Rate
Source: https://docs.tryprofound.com/rest-api/reports/query-shopping-trigger-rate-v2
POST /v2/reports/shopping/trigger-rate
This report shows how often ChatGPT returns shopping results for your prompts.
It gives the total runs, the shopping-triggered runs, and the trigger rate.
* **Metrics:** `total_runs`, `shopping_triggered_runs`, `trigger_rate_percentage`. `trigger_rate_percentage` is `shopping_triggered_runs / total_runs`. It is a **0–1 fraction**, not 0–100. To get a percent, multiply the value by 100.
* **`group_by`:** `date`, `topic`, `region`, `persona`, `prompt`.
* **Filter fields:** `topic`, `region`, `persona`, `prompt`, `tag`.
To get the rate for each prompt, add `prompt` to `group_by`. To get the rate for
each topic, add `topic`. To get a time series, add `date` and set `interval`.
Shopping data comes from ChatGPT only. No shopping report has a `model`
group\_by or a `model` filter.
The v2 reports share one request shape. For the filter tree, grouping, and
pagination, see [Filtering & concepts](/rest-api/reports/reports-v2-overview).
`POST /v2/reports/shopping/trigger-rate/stream` uses the **same request
body**. It returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event for each row.
The stream rejects `limit` and `cursor`. It returns all rows by default. To
set a maximum, use `max_results` (maximum 50000).
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/shopping/trigger-rate \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"group_by": ["date"],
"metrics": ["total_runs", "shopping_triggered_runs", "trigger_rate_percentage"],
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 30,
"count": 10,
"next_cursor": "eyJvZmZzZXQiOjEwfQ==",
"models": ["ChatGPT"],
"metrics": ["total_runs", "shopping_triggered_runs", "trigger_rate_percentage"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": null
},
"data": [
{
"date": "2026-06-01",
"total_runs": 1240,
"shopping_triggered_runs": 388,
"trigger_rate_percentage": 0.313
}
]
}
```
# Visibility
Source: https://docs.tryprofound.com/rest-api/reports/query-visibility-v2
POST /v2/reports/visibility
How often your asset appears in AI answers, plus share of voice and average
position. Select the asset(s) with `assets`, break results down with
`group_by`, and read each metric as a named field on the row.
* **Metrics:** `visibility_score` (share of answers the asset appeared in), `share_of_voice` (share of all mentions), `average_position` (average rank when mentioned; **lower is better**).
* **`group_by`:** `date`, `model`, `topic`, `region`, `prompt`, `persona`.
* **Select assets** with the `assets` param (a name, a list, or `{ op, value }`). `scope: "all"` ranks every asset; `"owned"` returns only yours.
* **`sort`** by any requested metric, e.g. `{ "field": "visibility_score" }`.
New to the v2 reports? See [Filtering & concepts](/rest-api/reports/reports-v2-overview) for the shared request shape, filter tree, grouping, and pagination.
`POST /v2/reports/visibility/stream` takes the **same request body** and
returns [Server-Sent Events](https://developer.mozilla.org/docs/Web/API/Server-sent_events):
one `summary` event (the `info` block), then one `result` event per row.
`limit`/`cursor` are ignored; it returns everything by default. Pass
`max_results` to cap.
```text Response (text/event-stream) theme={null}
event: summary
data: { ...the info block... }
event: result ← one per row, same shape as data[] above
data: {"asset": {"name": "Profound", "owned": true}, "rank": 1, "visibility_score": 0.48}
```
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/visibility \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-09",
"end_date": "2026-06-15"
}'
```
```json 200 theme={null}
{
"info": {
"total_results": 1,
"count": 1,
"next_cursor": null,
"scope": "owned",
"models": ["ChatGPT", "Google Gemini", "Perplexity", "Claude", "..."],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"asset_filter": null,
"filter": null
},
"data": [
{
"asset": { "name": "Profound", "owned": true },
"rank": 1,
"visibility_score": 0.48,
"share_of_voice": 0.077,
"average_position": 2.5
}
]
}
```
# Channels
Source: https://docs.tryprofound.com/rest-api/reports/query-youtube-channels-v2
POST /v2/reports/social/youtube/channels
Rank the YouTube channels cited in a category, or the video categories they publish in.
Rank the YouTube channels cited in a category, or the video categories they
publish in. Calculated from Profound's citation data, not YouTube analytics.
* **Source types:** `video`, `short`, `channel`, `playlist`, or `other`.
Omit `source_types` to include `video`, `short`, `channel`, and `playlist`.
Provide a non-empty list; duplicate values are de-duplicated. Rollups
cannot include `other`, because those citations have no channel.
* **`group_by`:** `channel` (the default), `video_category`, or `source_type`.
Supported cross-tabs are `["channel", "video_category"]`,
`["channel", "source_type"]`, and `["channel", "model"]`. Duplicate
dimensions are rejected.
* **Time series:** Set `interval` to `day`, `week`, or `month` to return one
row per entity per period. `date` is the bucket start in ET, so a weekly or
monthly bucket can start before `start_date`. Omit it for window totals.
* **Rows:** Fields are conditional: `date`, `model`, `source_type`, and
`video_category` appear only with the matching `interval` or `group_by`.
With `group_by: ["video_category"]`, the category is returned in `name`, not
`video_category`. An unresolved video category is returned as `""`, not
`null`. `rank` is the leading channel's rank in the full ranked set and is
repeated across that channel's cross-tab rows.
* **Pagination:** `limit` defaults to 10 and accepts 1–50. Pass the opaque
`info.next_cursor` back as the request `cursor` to get the next page;
`info` echoes your `cursor` on pages after the first. The response `info`
echoes `category_id`, the effective `limit`, and `interval`.
* **Totals:** `total_results` counts distinct channels in the window, while
`count` is the number of rows returned; they use different units.
* **Filters:** Prompt-level fields are `model`, `topic`, `region`, `prompt`,
`persona`, `tag`, and `analysis_type`. The `channel` filter accepts `is`,
`in`, `contains`, `not_contains`, `contains_case_insensitive`, and
`not_contains_case_insensitive`: `is`/`in` select exact handles, while the
other operators match channel titles or handles.
`domain` and `page` are rejected. A `channel` leaf cannot share an `or` or
`not` with a prompt-level leaf; put separate layers in `and` clauses.
For cross-tabs, `limit` counts leading channels, not returned rows. For
example, `limit: 25` with `group_by: ["channel", "video_category"]` returns
25 channels but can return more than 25 rows.
The v2 reports share a request shape and filter tree. See
[Filtering & concepts](/rest-api/reports/reports-v2-overview) for filter
operators, grouping, date ranges, pagination, and filter depth.
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/social/youtube/channels \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"group_by": ["channel", "source_type"],
"source_types": ["video", "short"],
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"total_results": 137,
"count": 2,
"next_cursor": "eyJvIjoxMH0",
"limit": 10,
"interval": null,
"group_by": ["channel", "source_type"],
"models": ["ChatGPT", "Google Gemini"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": null,
"source_types": ["video", "short"]
},
"data": [
{
"name": "Example Channel",
"handle": "examplechannel",
"url": "https://www.youtube.com/@examplechannel",
"rank": 1,
"source_type": "video",
"count": 128,
"videos": 14,
"citation_share": 0.37
},
{
"name": "Example Channel",
"handle": "examplechannel",
"url": "https://www.youtube.com/@examplechannel",
"rank": 1,
"source_type": "short",
"count": 42,
"videos": 8,
"citation_share": 0.12
}
]
}
```
# Videos
Source: https://docs.tryprofound.com/rest-api/reports/query-youtube-videos-v2
POST /v2/reports/social/youtube/videos
Rank cited YouTube videos, for one channel or across all of them.
Rank cited YouTube videos, for one channel or across all of them. Calculated
from Profound's citation data, not YouTube analytics.
* **Source types:** `video`, `short`, `channel`, `playlist`, or `other`.
`other` is available with `unattributed` or `all`; with the default
`attributed` mode, requests containing `other` are rejected. Omit
`source_types` to return `video` and `short` with the default `attributed`
mode; `unattributed` and `all` widen the default to all five source types.
Provide a non-empty list; duplicate values are de-duplicated.
* **Attribution:** `attributed` (the default), `unattributed`, or `all`.
An unattributed row has no channel: `source_type` is `other` for a search or
feed URL that names no source, and any other type is a source we have no
channel for.
* **Grouping and time series:** Not supported. `/videos` accepts no `group_by`
or `interval`; unknown fields are rejected.
* **Pagination:** `limit` defaults to 10 and accepts 1–50. Pass the opaque
`info.next_cursor` back as the request `cursor` to get the next page;
`info` echoes your `cursor` on pages after the first. The response `info`
echoes `category_id`, the effective `limit`, and `attribution`.
* **Filters:** Prompt-level fields are `model`, `topic`, `region`, `prompt`,
`persona`, `tag`, and `analysis_type`. The `channel` filter accepts `is`,
`in`, `contains`, `not_contains`, `contains_case_insensitive`, and
`not_contains_case_insensitive`: `is`/`in` select exact handles, while the
other operators match channel titles or handles.
`domain` and `page` are rejected. A `channel` leaf cannot share an `or` or
`not` with a prompt-level leaf; put separate layers in `and` clauses.
The v2 reports share a request shape and filter tree. See
[Filtering & concepts](/rest-api/reports/reports-v2-overview) for filter
operators, date ranges, pagination, and filter depth. Grouping and time
series guidance does not apply to this endpoint.
```bash cURL theme={null}
curl -X POST https://api.tryprofound.com/v2/reports/social/youtube/videos \
-H "X-API-Key: " \
-H "Content-Type: application/json" \
-d '{
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": {
"field": "channel",
"op": "in",
"value": ["examplechannel"]
},
"attribution": "attributed",
"limit": 10
}'
```
```json 200 theme={null}
{
"info": {
"category_id": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
"total_results": 1,
"count": 1,
"next_cursor": null,
"limit": 10,
"attribution": "attributed",
"models": ["ChatGPT", "Google Gemini"],
"start_date": "2026-06-01",
"end_date": "2026-06-30",
"filter": {
"field": "channel",
"op": "in",
"value": ["examplechannel"]
},
"source_types": ["video", "short"]
},
"data": [
{
"video_id": "dQw4w9WgXcQ",
"source_type": "video",
"title": "Example Video",
"channel_title": "Example Channel",
"channel_handle": "examplechannel",
"url": "https://www.youtube.com/watch?v=dQw4w9WgXcQ",
"channel_url": "https://www.youtube.com/@examplechannel",
"rank": 1,
"published_at": "2026-06-12",
"duration_seconds": 245,
"video_category": "Education",
"count": 73,
"citation_share": 0.21
}
]
}
```
# Filtering & concepts
Source: https://docs.tryprofound.com/rest-api/reports/reports-v2-overview
How the v2 report endpoints work: the shared request shape, the filter tree, grouping, scope, pagination, and streaming.
The v2 report endpoints share **one request and response shape**:
[Visibility](/rest-api/reports/query-visibility-v2),
[Citations](/rest-api/reports/query-citations-v2),
[Sentiment](/rest-api/reports/query-sentiment-v2),
[Query Fanouts](/rest-api/reports/query-fanouts-v2),
[Answers](/rest-api/reports/query-answers-v2), and
[FactCheck](/rest-api/reports/query-factcheck-v2) (accuracy scores +
[claims](/rest-api/reports/query-factcheck-claims-v2)). Learn it once and every
report works the same way. YouTube social reports are also v2 reports, with
channel and video-specific grouping and attribution fields; see
[YouTube Channels](/rest-api/reports/query-youtube-channels-v2) and
[YouTube Videos](/rest-api/reports/query-youtube-videos-v2) for their
endpoint-specific request and response fields.
FactCheck uses the same `{ info, data }` envelope but is **per-category** (no
`scope`/`assets`/`metrics` params) and takes a **narrower `filter`** — a
top-level `and` of single-field leaves, only `topic` negatable. See its pages
for specifics.
All v2 endpoints accept **names or UUIDs** anywhere a filter takes a value.
Get UUIDs from `GET /v1/org/models`, `/v1/org/regions`, `/v1/org/personas`,
`/v1/org/assets`, `/v1/org/categories`, and the per-category
`…/topics`, `…/tags`, `…/prompts` endpoints.
## Common request fields
| Field | Type | Notes |
| ------------------------- | ------------------------ | ------------------------------------------------------------------------------------ |
| `category_id` | UUID (required) | The category to query. |
| `start_date` / `end_date` | date (required) | `YYYY-MM-DD`, Eastern Time, **inclusive** on both ends. |
| `scope` | `owned` · `all` | Restrict to your owned assets/domains, or rank everything. Defaults vary per report. |
| `group_by` | string\[] | Break results into rows by dimension (see [Grouping](#grouping)). |
| `metrics` | string\[] | Which metrics to compute. Returned as **named fields on each row**. |
| `interval` | `day` · `week` · `month` | Bucket size when grouping by `date`. Default `day`. |
| `filter` | tree | `and`/`or`/`not`/leaf tree (see [Filters](#filters)). |
| `sort` | `{ field, dir }` | Order rows (where supported). |
| `limit` | `1`–`50` | Rows per page. Default `10`. |
| `cursor` | string | Page token from `info.next_cursor`. |
Unlike the v1 reports (where `end_date` is exclusive), **v2 `end_date` is
inclusive**. To get June 9–15, send `start_date: "2026-06-09"`,
`end_date: "2026-06-15"`.
## Grouping
`group_by` turns one aggregate row into one row per value. Each grouped field
is echoed back on the row:
```json theme={null}
// group_by: ["model"] → each row carries the model it's for
{ "asset": { "name": "Profound", "owned": true }, "model": { "id": "…", "name": "ChatGPT" }, "visibility_score": 0.52 }
```
* Group by `date` (with `interval`) for a time series.
* Rows carry a `rank` when grouped by a **non-date** dimension.
* Available dimensions differ per report; see each endpoint's reference.
## Metrics
Request the metrics you want; they come back as **named fields** on each row
(no positional arrays, no `info.query` lookup):
```json theme={null}
{ "rank": 1, "visibility_score": 0.48, "share_of_voice": 0.077, "average_position": 2.5 }
```
## Scope and asset selection
* **`scope`:** `owned` limits to assets/domains you own; `all` ranks across everything.
* **Visibility only:** pick the asset(s) with the separate **`assets`** param: a
name (`is`), a list (`in`, which overrides `scope`), or `{ op, value }`. A
selection returns all matches and ignores `limit`.
* **Sentiment** requires an **`asset`** (sentiment is per-brand).
## Filters
`filter` is a recursive tree, **max depth 3**, for every report, including
YouTube social reports:
```json theme={null}
{
"and": [
{ "or": [ { "field": "model", "op": "is", "value": "ChatGPT" },
{ "field": "model", "op": "is", "value": "Perplexity" } ] },
{ "not": { "field": "region", "op": "is", "value": "United States" } }
]
}
```
Node types: `{ "and": [ … ] }`, `{ "or": [ … ] }`, `{ "not": }`, and
leaves `{ "field", "op", "value" }`.
### Operators
| Operator | Meaning |
| ------------------------------------------------------------- | ------------------------------------------------------------------- |
| `is` / `not_is` | Exact match / negated |
| `in` / `not_in` | Match any value in a list (non-empty) / negated |
| `contains` / `not_contains` | Substring (case-sensitive) |
| `contains_case_insensitive` / `not_contains_case_insensitive` | Substring (case-insensitive) |
| `matches` | Regex (pattern ≥ 3 chars) |
| `exists` | Has any value; only on `tag` / `persona` (wrap in `not` for "none") |
`value` is a single value, or a list for `in` / `not_in`. Names **or** UUIDs;
`contains` / `matches` match on names.
### Two filter layers
Fields fall into two layers. They combine with `and`; **`or`/`not` can't mix
layers** (doing so returns `422`).
**Prompt layer** (full tree, full operator set):
`model`, `topic`, `region`, `persona`, `prompt`, `tag`.
**Entity / citation layer** (top-level `and` leaves only, varies per report):
| Report | Entity-layer fields |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Visibility | The entity (`asset`) uses the **`assets`** param, *not* `filter`. |
| Citations | `domain` (full ops, subdomain-aware), `page` (full ops), `analysis_type` (`visibility`·`sentiment`·`factcheck`·`all`), `citation_category` (`owned`·`competition`·`social`·`earned_media`·`earned_institutions`·`pr_wire`·`other`·custom), `citation_tag` (your custom tags; `is`/`in`) |
| Sentiment | `theme` / `claim`: `is`/`in`, single value, name or id |
| Query Fanouts | `analysis_type` (`visibility`·`sentiment`·`factcheck`·`all`), `is`/`in` |
| Answers | `analysis_type` is **prompt-level** (`visibility`·`sentiment`·`factcheck`; `is`/`in`/`not_in`; omit = all). `domain`/`page` are top-level `and` leaves: `is` one value or `in` a list (exact cited-URL match) |
| YouTube social | `channel` is the entity-layer filter. `domain` and `page` do not apply because YouTube rows are already scoped to YouTube sources. |
For citations, filter `domain` in the domains report and `page` when you
`group_by: ["page"]`; each filters its own report's entity.
YouTube reports use the `channel` entity filter. It can be combined with
prompt-level filters using `and`, but not with them under `or` or `not`.
YouTube `domain` and `page` filters are rejected rather than approximated.
List a category's citation tags with [Get Citation Tags](/api-reference/organization/get-category-citation-tags).
Put every tag you want in a single `in` leaf (values are OR'd) — AND-ing two
separate `citation_tag` leaves, or passing an empty list, returns `422`.
## Sorting
Where supported, `sort` is `{ "field": "", "dir": "asc" | "desc" }`.
The field must be a requested, sortable metric (or `date` when grouped by
date). **Citations has no `sort`:** it's always ranked most-cited first.
## Pagination
Responses return `limit` rows plus `info.next_cursor`. Pass that token back as
`cursor` to get the next page; `next_cursor` is `null` on the last page.
## Streaming
Every report endpoint except YouTube social reports has a **`/stream`** variant
(Server-Sent Events): a `summary` event (the `info` block), then one `result`
event per row. `limit`/`cursor` are ignored; it returns everything by default.
Pass `max_results` to cap.
## Response shape
Every report returns `{ info, data }`:
```json theme={null}
{
"info": {
"total_results": 8427,
"count": 10,
"next_cursor": "…",
"models": ["ChatGPT", "Google Gemini", "..."],
"start_date": "2026-06-09",
"end_date": "2026-06-15",
"filter": null
},
"data": [
{ "rank": 1, "visibility_score": 0.48 }
]
}
```
`info` echoes the resolved query (models in scope, the applied filter, dates,
pagination); `data` is the rows, with metrics as named fields and any
`group_by` dimensions attached.
# Response Format
Source: https://docs.tryprofound.com/rest-api/response-format
Understanding report response structures and data interpretation
## Overview
Report endpoints (`/v1/reports/*`) use a specialized array-based response format to optimize performance and reduce payload size. This guide explains how to interpret these responses.
Other endpoints like `/v1/org/*` and `/v1/prompts/*` use standard JSON object
structures that are documented in the OpenAPI reference.
## Report Response Structure
All report endpoints return data in this optimized format:
```json theme={null}
{
"data": [
{
"dimensions": ["example.com", "/some/path", "2023-10-01"],
"metrics": [10, 0.05]
},
{
"dimensions": ["another-site.com", "/different/path", "2023-10-02"],
"metrics": [15, 0.08]
}
],
"info": {
"query": {
"date_interval": "day",
"dimensions": ["hostname", "path", "date"],
"filters": [
{
"field": "hostname",
"operator": "in",
"value": ["example.com", "another-site.com"]
}
],
"metrics": ["count", "share_of_voice"]
},
"total_rows": 200
}
}
```
## Interpreting Report Data
### Array Position Mapping
The key to understanding report responses is that array positions correspond exactly to your request parameters:
#### Dimensions Array
Values map to the order of dimensions in your request:
* `dimensions[0]` → First dimension requested (`hostname`)
* `dimensions[1]` → Second dimension requested (`path`)
* `dimensions[2]` → Third dimension requested (`date`)
#### Metrics Array
Values map to the order of metrics in your request:
* `metrics[0]` → First metric requested (`count`)
* `metrics[1]` → Second metric requested (`share_of_voice`)
#### Example Mapping
For the first result object above:
* **Hostname**: `dimensions[0]` = "example.com"
* **Path**: `dimensions[1]` = "/some/path"
* **Date**: `dimensions[2]` = "2023-10-01"
* **Count**: `metrics[0]` = 10
* **Share of Voice**: `metrics[1]` = 0.05
### Info Object
The `info` object provides metadata about your query:
| Field | Description |
| ------------ | --------------------------------------------------------- |
| `query` | Your exact request parameters echoed back |
| `total_rows` | Total number of results available (useful for pagination) |
## Working with Report Responses
### Processing Data
Example of converting the array format to a more traditional object structure:
```javascript JavaScript theme={null}
// Process report response
const processReportData = (response) => {
const { dimensions: dimNames, metrics: metricNames } = response.info.query;
return response.data.map(row => {
const result = {};
// Map dimensions
dimNames.forEach((name, index) => {
result[name] = row.dimensions[index];
});
// Map metrics
metricNames.forEach((name, index) => {
result[name] = row.metrics[index];
});
return result;
});
};
// Usage
const processedData = processReportData(apiResponse);
// Result: [{ hostname: "example.com", path: "/some/path", date: "2023-10-01", count: 10, share_of_voice: 0.05 }]
```
```python Python theme={null}
def process_report_data(response):
"""Convert array-based response to dict format"""
query_info = response['info']['query']
dim_names = query_info['dimensions']
metric_names = query_info['metrics']
results = []
for row in response['data']:
result = {}
# Map dimensions
for i, name in enumerate(dim_names):
result[name] = row['dimensions'][i]
# Map metrics
for i, name in enumerate(metric_names):
result[name] = row['metrics'][i]
results.append(result)
return results
# Usage
processed_data = process_report_data(api_response)
# Result: [{"hostname": "example.com", "path": "/some/path", "date": "2023-10-01", "count": 10, "share_of_voice": 0.05}]
```
```php PHP theme={null}
function processReportData($response) {
$queryInfo = $response['info']['query'];
$dimNames = $queryInfo['dimensions'];
$metricNames = $queryInfo['metrics'];
$results = [];
foreach ($response['data'] as $row) {
$result = [];
// Map dimensions
foreach ($dimNames as $index => $name) {
$result[$name] = $row['dimensions'][$index];
}
// Map metrics
foreach ($metricNames as $index => $name) {
$result[$name] = $row['metrics'][$index];
}
$results[] = $result;
}
return $results;
}
```
## Best Practices
1. **Always use the `info.query` object** to understand the structure of your response data
2. **Process responses programmatically** using the mapping examples above rather than hardcoding array positions
3. **Handle pagination** using the `total_rows` field to determine if more data is available
4. **Monitor rate limit headers** to avoid hitting API limits
5. **Validate your request parameters** match the expected dimensions and metrics for your use case
## Need Help?
If you encounter unexpected response formats or need clarification on specific report responses, contact our support team for assistance.
# JavaScript Package
Source: https://docs.tryprofound.com/sdks/javascript-package
# SDKs
Source: https://docs.tryprofound.com/sdks/overview
Official Python and JavaScript SDKs for the Profound API
## Overview
Profound provides official SDKs for Python and JavaScript/TypeScript, making it easier to integrate our API into your applications.
**Key benefits:**
* Type-safe interfaces with full TypeScript support
* Automatic authentication handling
* Built-in retry logic and error handling
* Comprehensive code examples for every endpoint
* Async/await support for modern applications
All API endpoint documentation includes code samples in both Python and JavaScript. View the **Endpoints** section in the REST API tab to see examples for specific operations.
## Installation
```bash Python theme={null}
pip install profound
```
```bash JavaScript theme={null}
npm install @profoundai/client
# or
yarn add @profoundai/client
# or
pnpm add @profoundai/client
# or
bun add @profoundai/client
```
## Quick Start
### Python
```python theme={null}
from profound import Profound
client = Profound(
api_key="your-api-key-here" # or set PROFOUND_API_KEY env var
)
# Get organization categories
categories = client.organizations.categories.list()
print(categories)
# Generate a report
report = client.reports.visibility(
category_id=categories[0]['id'],
start_date="2024-01-01",
end_date="2024-01-31",
dimensions=["asset_name"],
metrics=["visibility_score"]
)
print(report)
```
### JavaScript/TypeScript
```typescript theme={null}
import Profound from '@profoundai/client';
const client = new Profound({
apiKey: "your-api-key-here" // or set PROFOUND_API_KEY env var
});
// Get organization categories
const categories = await client.organizations.categories.list();
console.log(categories);
// Generate a report
const report = await client.reports.visibility({
category_id: categories[0].id,
start_date: "2024-01-01",
end_date: "2024-01-31",
dimensions: ["asset_name"],
metrics: ["visibility_score"]
});
console.log(report);
```
## Authentication
Both SDKs support multiple authentication methods:
1. **Environment variable** (recommended): Set `PROFOUND_API_KEY` in your environment
2. **Constructor parameter**: Pass `api_key` (Python) or `apiKey` (JavaScript) when initializing the client
```bash theme={null}
# Set environment variable
export PROFOUND_API_KEY="your-api-key-here"
```
For more details on obtaining an API key, see [Authentication](/rest-api/authentication).
## Error Handling
### Python
```python theme={null}
from profound import Profound, APIError
client = Profound()
try:
report = client.reports.visibility(
category_id="invalid-id",
start_date="2024-01-01",
end_date="2024-01-31",
dimensions=["asset_name"],
metrics=["visibility_score"]
)
except APIError as e:
print(f"API Error: {e.status_code} - {e.message}")
```
### JavaScript/TypeScript
```typescript theme={null}
import Profound from '@profoundai/client';
const client = new Profound();
try {
const report = await client.reports.visibility({
category_id: 'invalid-id',
start_date: '2024-01-01',
end_date: '2024-01-31',
dimensions: ['asset_name'],
metrics: ['visibility_score']
});
} catch (error) {
if (error instanceof Profound.APIError) {
console.error(`API Error: ${error.status} - ${error.message}`);
}
}
```
## Rate Limiting
The API has a default limit of 600 requests per hour per API key. When you exceed this limit, you'll receive a `429 Too Many Requests` error. Both SDKs will throw an error that you can catch and handle appropriately.
```python theme={null}
# Python
from profound import RateLimitError
try:
report = client.reports.visibility(...)
except RateLimitError as e:
print("Rate limit exceeded. Please wait before retrying.")
```
```typescript theme={null}
// JavaScript
import Profound from '@profoundai/client';
try {
const report = await client.reports.visibility(...);
} catch (error) {
if (error instanceof Profound.RateLimitError) {
console.log('Rate limit exceeded. Please wait before retrying.');
}
}
```
## Async Support
### Python
The Python SDK supports both synchronous and asynchronous usage:
```python theme={null}
# Synchronous
from profound import Profound
client = Profound()
categories = client.organizations.categories.list()
# Asynchronous
from profound import AsyncProfound
import asyncio
async def main():
client = AsyncProfound()
categories = await client.organizations.categories.list()
asyncio.run(main())
```
### JavaScript
The JavaScript SDK is fully async/await based:
```typescript theme={null}
import Profound from '@profoundai/client';
const client = new Profound();
// All methods return promises
const categories = await client.organizations.categories.list();
```
## Code Examples
Every endpoint in our API documentation includes working code samples for both SDKs. Browse the **Endpoints** section in the REST API tab to see specific examples for:
* Organization management
* Category discovery
* Report generation
* Raw data access
* And more
## Support & Resources
* **Python Package**: [PyPI](https://pypi.org/project/profound/)
* **JavaScript Package**: [npm](https://www.npmjs.com/package/@profoundai/client)
* **API Documentation**: [REST API Introduction](/rest-api/introduction)
* **Support**: [support@tryprofound.com](mailto:support@tryprofound.com)
SDK interfaces may change as we improve the API. We recommend pinning to specific versions in production environments.
# Python Package
Source: https://docs.tryprofound.com/sdks/python-package