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

# Ad Feedback

> Let users react to ads with thumbs-up / thumbs-down.

End users can submit feedback on served ads — thumbs up, thumbs down, and optional reasons. This helps Gravity improve ad quality and relevancy over time, and gives publishers a signal for user satisfaction.

## Base URL

```
https://platform.trygravity.ai
```

## Headers

<ParamField header="X-API-Key" type="string" required>
  Your Gravity publisher API key.
</ParamField>

## Body

<ParamField body="sessionId" type="string" required>
  Session identifier. Same value you passed when requesting the ad.
</ParamField>

<ParamField body="impUrl" type="string" required>
  The `impUrl` from the ad response object. The server decrypts this to extract the ad's tracking IDs (grclid, gradid, campaignId, publisherId) automatically — you don't need to parse or extract anything yourself.
</ParamField>

<ParamField body="sentiment" type="string" required>
  User's reaction. One of `thumbs_up` or `thumbs_down`.
</ParamField>

<ParamField body="reasons" type="array">
  Optional. Why the user reacted this way. Array of reason strings. Suggested values:

  | Reason           | When to use                                   |
  | ---------------- | --------------------------------------------- |
  | `not_interested` | User doesn't care about this product/category |
  | `irrelevant`     | Ad doesn't relate to the conversation         |
  | `offensive`      | Ad content is objectionable                   |
  | `repetitive`     | User has seen this ad too many times          |
  | `misleading`     | Ad claims don't match the landing page        |
  | `helpful`        | (thumbs up) Ad was useful or well-matched     |

  You can send any string — the values above are suggestions, not an enum.
</ParamField>

<ParamField body="comment" type="string">
  Optional. Free-text feedback from the user (max 1,000 characters).
</ParamField>

<ParamField body="placement" type="string">
  Optional. Placement type where the ad was shown (e.g. `below_response`).
</ParamField>

<ParamField body="placementId" type="string">
  Optional. Publisher's slot identifier for the placement.
</ParamField>

<ParamField body="userId" type="string">
  Optional. Publisher's end-user identifier.
</ParamField>

<ParamField body="device" type="object">
  Optional. Device signals — same shape as the ad request's `device` object.
</ParamField>

<RequestExample>
  ```bash theme={null}
  curl -X POST https://platform.trygravity.ai/ad-feedback \
    -H "X-API-Key: <your_publisher_api_key>" \
    -H "Content-Type: application/json" \
    -d '{
      "sessionId": "sess_abc123",
      "impUrl": "https://api.trygravity.ai/ack?p=<encrypted_token_from_ad_response>",
      "sentiment": "thumbs_down",
      "reasons": ["not_interested", "repetitive"]
    }'
  ```
</RequestExample>

## Response

**`200`** — feedback recorded.

```json theme={null}
{
  "status": "ok",
  "feedbackId": "f47ac10b-58cc-4372-a567-0e02b2c3d479"
}
```

**`401`** — invalid API key.

**`422`** — invalid `impUrl`. The URL could not be decrypted. Make sure you're sending the exact `impUrl` from the ad response.

**`429`** — rate limit exceeded. The endpoint allows up to 30 feedback submissions per session per minute.

**`503`** — internal error. Safe to retry.

## Server-prompted feedback

Official Gravity SDKs show and submit feedback controls automatically when requested by the server. No publisher setup is required.

Custom renderers can use `feedbackPrompt` to decide when to show controls and POST the response to this endpoint. Feedback interactions must not count as ad clicks.

## Best practices

### Surface feedback controls after the ad renders

Show a small thumbs-up / thumbs-down UI once the ad is visible. Don't interrupt the user — feedback should be one tap, not a modal.

```tsx theme={null}
function AdWithFeedback({ ad, sessionId, apiKey }) {
  const [sent, setSent] = useState(false);

  const sendFeedback = async (sentiment, reasons) => {
    setSent(true);
    await fetch('https://platform.trygravity.ai/ad-feedback', {
      method: 'POST',
      headers: {
        'X-API-Key': apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        sessionId,
        impUrl: ad.impUrl,
        sentiment,
        reasons,
      }),
    });
  };

  if (sent) return <span>Thanks for the feedback</span>;

  return (
    <div>
      <GravityAd ad={ad} />
      <button onClick={() => sendFeedback('thumbs_up')}>👍</button>
      <button onClick={() => sendFeedback('thumbs_down', ['not_interested'])}>👎</button>
    </div>
  );
}
```

### Collect reasons on thumbs-down

When a user taps thumbs-down, show a quick follow-up with checkboxes or chips for `not_interested`, `irrelevant`, `repetitive`, `offensive`. Send the selected reasons in the `reasons` array. This gives Gravity actionable signal to improve matching.

### Don't gate the experience on feedback

Feedback is fire-and-forget. If the request fails, swallow the error — never block the user's workflow because a feedback call didn't land.

### Just pass through `impUrl`

Every ad response includes an `impUrl`. Simply store the ad object and pass `ad.impUrl` back when submitting feedback — the server handles all the tracking ID extraction automatically. No need to parse URLs or decrypt tokens on the client side.

## What's next

<CardGroup cols={2}>
  <Card title="Show ads" icon="eye" href="/ai-platforms/show-ads">
    Render ads with the pre-built React component or your own UI.
  </Card>

  <Card title="Contextual ads endpoint" icon="code" href="/engine/contextual-ads">
    Full request / response reference for `POST /api/v1/ad`.
  </Card>
</CardGroup>
