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

# Index Exchange

> Integrate with Index Exchange for SSP functionality

export const NoBadge = () => {
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.5rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: '#F7D0E2',
    color: '#1A1A1A',
    fontWeight: '500'
  }}>
      No
    </span>;
};

export const YesBadge = () => {
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.5rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: '#C7E8F9',
    color: '#1A1A1A',
    fontWeight: '500'
  }}>
      Yes
    </span>;
};

export const BadgeRowCenter = ({label, children}) => {
  return <div style={{
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginBottom: '0.5rem'
  }}>
      <span style={{
    fontSize: '0.625rem',
    color: '#6b7280',
    textTransform: 'uppercase',
    fontWeight: '500',
    letterSpacing: '0.05em'
  }}>
        {label}
      </span>
      {children}
    </div>;
};

export const BadgeRow = ({label, children}) => {
  return <div style={{
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'flex-start',
    marginBottom: '0.5rem'
  }}>
      <span style={{
    fontSize: '0.625rem',
    color: '#6b7280',
    textTransform: 'uppercase',
    fontWeight: '500',
    letterSpacing: '0.05em'
  }}>
        {label}
      </span>
      {children}
    </div>;
};

export const BadgeContainer = ({children}) => {
  return <div style={{
    display: 'flex',
    gap: '0.25rem',
    flexWrap: 'wrap',
    justifyContent: 'flex-end',
    minWidth: '0',
    flex: '1'
  }}>
      {children}
    </div>;
};

export const ProductRequiredBadge = ({product}) => {
  const getBadgeStyle = product => {
    switch (product) {
      case 'Core Platform':
        return {
          background: '#CB88FC',
          color: '#1A1A1A'
        };
        --purple;
      case 'Routing':
        return {
          background: '#CB88FC',
          color: '#1A1A1A'
        };
        --purple;
      case 'Contextual':
        return {
          background: '#CB88FC',
          color: '#1A1A1A'
        };
        --purple;
      default:
        return {
          background: '#A7B3D9',
          color: '#1A1A1A'
        };
        --haze;
    }
  };
  const style = getBadgeStyle(product);
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.375rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: style.background,
    color: style.color,
    fontWeight: '500'
  }}>
      {product}
    </span>;
};

export const SdkRequiredBadge = ({required}) => {
  const getBadgeStyle = required => {
    switch (required) {
      case 'Yes':
        return {
          background: '#C7E8F9',
          color: '#1A1A1A'
        };
        --blue;
      case 'No':
        return {
          background: '#F7D0E2',
          color: '#1A1A1A'
        };
        --pink;
      default:
        return {
          background: '#A7B3D9',
          color: '#1A1A1A'
        };
        --haze;
    }
  };
  const style = getBadgeStyle(required);
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.375rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: style.background,
    color: style.color,
    fontWeight: '500'
  }}>
      {required}
    </span>;
};

export const CapabilityBadge = ({capability}) => {
  const getBadgeStyle = capability => {
    switch (capability) {
      case 'Event Collection':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Cohort Activation':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Campaign Optimization':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Identity Signal':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Contextual Signal':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Connectivity':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Routing':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      case 'Data Collaboration':
        return {
          background: '#EFDFC8',
          color: '#1A1A1A'
        };
        --clay;
      default:
        return {
          background: '#A7B3D9',
          color: '#1A1A1A'
        };
        --haze;
    }
  };
  const style = getBadgeStyle(capability);
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.375rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: style.background,
    color: style.color,
    fontWeight: '500',
    whiteSpace: 'nowrap'
  }}>
      {capability}
    </span>;
};

export const EnvironmentBadge = ({environment}) => {
  const getBadgeStyle = environment => {
    switch (environment) {
      case 'Web':
        return {
          background: '#F9C1A8',
          color: '#1A1A1A'
        };
        --peach;
      case 'iOS':
        return {
          background: '#F9C1A8',
          color: '#1A1A1A'
        };
        --peach;
      case 'Android':
        return {
          background: '#F9C1A8',
          color: '#1A1A1A'
        };
        --peach;
      case 'CTV':
        return {
          background: '#F9C1A8',
          color: '#1A1A1A'
        };
        --peach;
      case 'API Direct':
        return {
          background: '#F9C1A8',
          color: '#1A1A1A'
        };
        --peach;
      default:
        return {
          background: '#A7B3D9',
          color: '#1A1A1A'
        };
        --haze;
    }
  };
  const style = getBadgeStyle(environment);
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.375rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: style.background,
    color: style.color,
    fontWeight: '500',
    whiteSpace: 'nowrap'
  }}>
      {environment}
    </span>;
};

export const DirectionBadge = ({direction}) => {
  const getBadgeStyle = direction => {
    switch (direction) {
      case 'Bidirectional':
        return {
          background: '#FA8784',
          color: '#1A1A1A'
        };
        --tomato;
      case 'Destination':
        return {
          background: '#FA8784',
          color: '#1A1A1A'
        };
        --tomato;
      case 'Source':
        return {
          background: '#FA8784',
          color: '#1A1A1A'
        };
        --tomato;
      default:
        return {
          background: '#A7B3D9',
          color: '#1A1A1A'
        };
        --haze;
    }
  };
  const style = getBadgeStyle(direction);
  return <span style={{
    display: 'inline-block',
    padding: '0.125rem 0.375rem',
    borderRadius: '0.25rem',
    fontSize: '0.625rem',
    background: style.background,
    color: style.color,
    fontWeight: '500'
  }}>
      {direction}
    </span>;
};

<Card title="">
  <div style={{ display: 'flex', alignItems: 'center', marginBottom: '1rem' }}>
    <div style={{ width: '32px', height: '32px', marginRight: '0.75rem', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
      <img src="https://mintcdn.com/permutive/tY6HQAw8J0a8II15/images/integrations/logos/index-exchange.png?fit=max&auto=format&n=tY6HQAw8J0a8II15&q=85&s=7e00590e2344275a71936b8bfb6321d8" alt="Index Exchange" style={{ maxWidth: '32px', maxHeight: '32px', display: 'block', backgroundColor: '#f3f4f6', borderRadius: '4px', padding: '2px' }} width="32" height="32" data-path="images/integrations/logos/index-exchange.png" />
    </div>

    <h3 style={{ margin: 0, fontSize: '1.125rem', fontWeight: '600' }}>Index Exchange</h3>
  </div>

  <div style={{ marginBottom: '1rem' }}>
    <BadgeRowCenter label="Direction">
      <DirectionBadge direction="Destination" />
    </BadgeRowCenter>

    <BadgeRowCenter label="Environment">
      <BadgeContainer>
        <EnvironmentBadge environment="Web" />
      </BadgeContainer>
    </BadgeRowCenter>

    <BadgeRowCenter label="Capability">
      <BadgeContainer>
        <CapabilityBadge capability="Cohort Activation" />
      </BadgeContainer>
    </BadgeRowCenter>

    <BadgeRowCenter label="SDK Required">
      <SdkRequiredBadge required="Yes" />
    </BadgeRowCenter>

    <BadgeRowCenter label="Product(s) Required">
      <ProductRequiredBadge product="Core Platform" />
    </BadgeRowCenter>
  </div>

  <p style={{ margin: 0, fontSize: '0.875rem', color: '#6b7280', lineHeight: '1.5' }}>
    Index Exchange is a global ad exchange that helps publishers connect with premium demand through real-time bidding.
  </p>
</Card>

<CardGroup cols={2}>
  <Card title="Setup" href="#setup" icon="gear" />

  <Card title="Troubleshooting" href="#troubleshooting" icon="wrench" />
</CardGroup>

## Overview

Index Exchange is a global ad exchange that helps publishers connect with premium demand through real-time bidding. The integration enables real-time cohort activation through Prebid.js, allowing advertisers to target your audiences programmatically via the Index Exchange SSP.

This integration is a Destination:

* **Destination:** Permutive cohorts are activated and passed to Index Exchange in real-time through bid requests, enabling advertisers to target your first-party audience segments programmatically.

Use cases include:

* **Cookie-less audience activation at scale:** Activate Permutive cohort signals programmatically via the bidstream without reliance on third-party cookies, enabling addressable reach across all users
* **Private Marketplace (PMP) deals:** Use Custom Cohorts, DCR Cohorts, and Curated Cohorts to create premium, curated inventory packages for direct buyer relationships
* **Open Marketplace (OMP) monetization:** Leverage Standard Cohorts to make your audiences available to demand partners in the open auction, increasing bid density and CPMs
* **Maximize programmatic yield:** Make Permutive audiences available through Index Exchange's ad exchange to increase competition and drive higher CPMs

**Cohort Support:**

* ✅ **Custom Cohorts** - Publisher-defined audiences created in the Permutive dashboard
* ✅ **Standard Cohorts** - Cohort signals conforming to a standardized taxonomy (e.g. IAB)
* ✅ **Curation Cohorts** - Curated cross-publisher signals from Permutive's Curation offering
* ✅ **Data Clean Room Cohorts** - Privacy-safe audience activation through Permutive's Data Clean Room

## Environment Compatibility

| Environment    | Supported    | Notes |
| -------------- | ------------ | ----- |
| **Web**        | <YesBadge /> | --    |
| **iOS**        | <NoBadge />  | --    |
| **Android**    | <NoBadge />  | --    |
| **CTV**        | <NoBadge />  | --    |
| **API Direct** | <NoBadge />  | --    |

## Prerequisites

* **Index Exchange SSP Account** - You must have an active Index Exchange SSP account
* **Permutive SDK** - The Permutive Web SDK must be deployed on your site
* **Prebid.js with Permutive RTD Module** - Prebid.js must be configured with the Permutive Real-Time Data (RTD) module to pass cohort data to Index Exchange
* **Bidder Adapter** - The [`ix`](https://docs.prebid.org/dev-docs/bidders/ix.html) bidder adapter must be configured in your Prebid.js setup (this is the bidder code for Index Exchange).

## Setup

<Tabs>
  <Tab title="Primary Setup Steps">
    <Steps>
      <Step title="Configure Cohort Activations">
        The Index Exchange SSP integration works automatically through Prebid.js once cohorts are activated. Navigate to the cohort you wish to activate in the Permutive dashboard.

        For **Custom Cohorts** (publisher-specific audiences), enable the Index Exchange SSP activation. When activated, cohort data will be stored in the `_pindexs` local storage key, which the Permutive RTD module reads and passes to Index Exchange.

        <Note>Custom Cohorts require explicit activation per cohort. Standard, Curated, and Data Clean Room cohorts are configured by your Customer Success Manager. Contact your CSM to enable these cohort types for your integration.</Note>
      </Step>

      <Step title="Verify Prebid.js Configuration">
        Ensure your Prebid.js configuration includes the Permutive RTD module with Index Exchange support:
        Verify that the Permutive SDK is loading correctly and that cohort data is being written to local storage.
      </Step>

      <Step title="Verify Setup">
        After activating cohorts and configuring Prebid.js, verify that cohort data is being passed to Index Exchange in bid requests.

        Use the **Professor Prebid Chrome extension** ([download here](https://chromewebstore.google.com/detail/professor-prebid/kdnllijdimhbledmfdbljampcdphcbdc)) to inspect bid requests:

        1. Install the Professor Prebid extension
        2. Open the extension while on your page
        3. Navigate to the "Bid Requests" tab
        4. Find Index Exchange (`ix`) bidder requests
        5. Verify that the ORTB2 object contains Permutive cohort data in `ortb2.user.data` and `ortb2.user.keywords`

        Alternatively, use browser developer tools to:

        1. Check local storage for the `_pindexs` key (Custom Cohorts) or `_pssps` key (Standard/Curated/DCR cohorts)
        2. Inspect network requests to Index Exchange endpoints
        3. Verify that the ORTB2 object in bid requests contains Permutive cohort data

        <Note>It may take a few minutes for cohort membership to populate after initial page load.</Note>
      </Step>
    </Steps>
  </Tab>

  <Tab title="Web">
    ### Integrate with Prebid.js

    The Index Exchange SSP integration works through the Permutive Real-Time Data (RTD) module in Prebid.js. The module reads cohort data from local storage (set by the Permutive SDK) and attaches it to bid requests as first-party data following OpenRTB 2.x conventions.

    #### Configuration

    In your Prebid.js configuration, include the Permutive RTD module:

    ```javascript theme={"dark"}
    pbjs.setConfig({
      realTimeData: {
        dataProviders: [
          {
            name: "permutive",
            waitForIt: true,
            params: {
              maxSegs: 500,
            },
          },
        ],
      },
    });
    ```

    #### How it Works

    The Index Exchange SSP integration operates through a client-side mechanism:

    **1. Local Storage Cohort Exposure**

    The Permutive Web SDK exposes cohort signals via local storage:

    * **Custom Cohorts**: Stored in the `_pindexs` local storage key
    * **Standard, Curated, and DCR Cohorts**: Stored in the `_pssps` local storage key

    **2. Real-Time Bid Enrichment**

    The Permutive RTD module acts as a bridge between the Permutive Web SDK and Prebid.js:

    1. The Permutive RTD module reads cohort IDs from local storage (`_pindexs` for Custom Cohorts, `_pssps` for Standard/Curated/DCR cohorts)
    2. Cohort data is attached to the ORTB2 object in bid requests for Index Exchange
    3. For Custom Cohorts, the module updates two locations:
       * `ortb2.user.data` – adds a data provider entry for `permutive.com` with the list of cohort IDs in the `segment` field
       * `ortb2.user.keywords` – adds a keyword group called `permutive` containing the list of cohort IDs
    4. Index Exchange receives cohort targeting data in the bid request and makes it available to demand partners (DSPs) for real-time targeting

    #### Consent

    While Permutive is listed as a TCF vendor (ID: 361), Permutive does not typically obtain vendor consent from the TCF, but instead relies on publisher purpose consents. Publishers wishing to use TCF vendor consent instead can add 361 to their CMP and set `params.enforceVendorConsent` to `true`:

    ```javascript theme={"dark"}
    pbjs.setConfig({
      realTimeData: {
        dataProviders: [{
          name: 'permutive',
          params: {
            enforceVendorConsent: true  // Require TCF vendor consent for Permutive (ID: 361)
          }
        }]
      }
    })
    ```

    For more details on Prebid.js configuration, see the [Prebid.js documentation](https://docs.prebid.org/dev-docs/modules/permutiveRtdProvider.html).
  </Tab>
</Tabs>

## Data Types

The Index Exchange SSP integration is a destination-only integration focused on cohort activation. Permutive does not collect event data from Index Exchange SSP.

When cohorts are activated to Index Exchange, the following data is transmitted via the Prebid.js bidstream:

<AccordionGroup>
  <Accordion title="ORTB2 Signal Locations">
    Permutive passes cohort data to Index Exchange SSP via the ORTB2 object in Prebid.js bid requests. Different cohort types are written to specific ORTB2 locations:

    | ORTB2 Location                            | Cohort Types                                   |
    | ----------------------------------------- | ---------------------------------------------- |
    | `ortb2.user.data` (name: `permutive.com`) | Standard Cohorts, DCR Cohorts, Curated Cohorts |
    | `ortb2.user.data` (name: `permutive`)     | Custom Cohorts                                 |
    | `ortb2.user.keywords` (`permutive`)       | Custom Cohorts                                 |
    | `ortb2.user.keywords` (`p_standard`)      | Standard Cohorts, DCR Cohorts, Curated Cohorts |
    | `ortb2.user.keywords` (`p_standard_aud`)  | Curated Cohorts                                |
  </Accordion>

  <Accordion title="Local Storage Keys">
    The Permutive Web SDK exposes cohort data via local storage, which the Permutive RTD module reads to populate bid requests.

    <ResponseField name="_pindexs" type="array">
      Local storage key containing Custom Cohort IDs for Index Exchange.
    </ResponseField>

    <ResponseField name="_pssps" type="object">
      Local storage key containing Standard Cohorts, Curated Cohorts, and Data Clean Room Cohorts.
    </ResponseField>
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Cohort data not appearing in bid requests">
    If Permutive cohorts aren't being passed to Index Exchange in your bid requests:

    * Verify that the Permutive RTD module is properly configured in your Prebid.js setup
    * Confirm that the Permutive SDK is loading correctly on your pages
    * Use browser developer tools to inspect local storage and verify that the `_pindexs` key (for Custom Cohorts) or `_pssps` key (for Standard/Curated/DCR cohorts) contains cohort data
    * Check your Prebid.js console logs for any errors related to the Permutive RTD module
    * Use the **Professor Prebid Chrome extension** to inspect ORTB2 data being sent to Index Exchange bid requests
    * Inspect network requests to Index Exchange endpoints to verify ORTB2 data is present

    <Note>If you see cohort data in local storage but not in bid requests, verify that your Prebid.js configuration includes `waitForIt: true` for the Permutive RTD module.</Note>
  </Accordion>

  <Accordion title="Empty _pindexs or _pssps local storage keys">
    If local storage keys are empty or missing:

    * Verify that Custom Cohorts have been activated in the Permutive dashboard with Index Exchange SSP enabled
    * Check that users actually qualify for the activated cohorts based on cohort definitions
    * Ensure the Permutive SDK is loading before Prebid.js attempts to read cohort data
    * Verify that third-party cookies and local storage are not blocked by browser settings or extensions
    * Check the browser console for any Permutive SDK errors during page load
  </Accordion>

  <Accordion title="Cohorts visible in local storage but not in Index Exchange UI">
    If cohorts are being passed in bid requests but you don't see them available for targeting in the Index Exchange UI:

    * Verify with your Index Exchange account team that your SSP seat is configured to receive and process Permutive cohort data
    * Check that DSPs connected to your Index Exchange seat have access to user data signals from the bid request
    * Ensure that your Index Exchange line items or deals are configured to accept and use targeting data from the bid stream
    * Confirm that the ORTB2 data structure matches Index Exchange's expectations for user data and keywords
  </Accordion>

  <Accordion title="GDPR/consent issues blocking cohort signals">
    In GDPR regions, consent management may affect cohort data transmission:

    * **Note:** Permutive is a TCF vendor (ID: 361), but by default relies on publisher purpose consents rather than TCF vendor consent
    * If you've enabled `params.enforceVendorConsent: true`, verify that Permutive (vendor ID 361) is added to your CMP and consent is being collected
    * Verify that your Consent Management Platform (CMP) is properly configured and Permutive has consent to process user data
    * Check that the Permutive SDK is receiving consent signals correctly
    * Ensure Prebid.js is configured to respect consent signals and only pass data when consent is granted
  </Accordion>

  <Accordion title="Professor Prebid extension not showing Index Exchange bids">
    If you're not seeing Index Exchange bid requests in the Professor Prebid Chrome extension:

    * Verify that the `ix` bidder adapter is properly configured in your Prebid.js setup
    * Check that Index Exchange is enabled and actively bidding on your inventory
    * Ensure you're viewing the correct page where Index Exchange bidder is configured
    * Try refreshing the page with the extension open to capture new bid requests
    * Check your Prebid.js console logs to confirm Index Exchange bidder is being called
  </Accordion>
</AccordionGroup>

## Changelog

<Info>
  For detailed changelog information, visit our
  [Changelog](https://changelog.permutive.com/).
</Info>
