> ## 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.

# Apester

> Integrate with Apester for survey data collection

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/Juzd3YB8HgaWRAEF/images/integrations/logos/apester.png?fit=max&auto=format&n=Juzd3YB8HgaWRAEF&q=85&s=74b62877d962cbbdb7785d8654d3783b" alt="Apester" style={{ maxWidth: '32px', maxHeight: '32px', display: 'block' }} width="60" height="61" data-path="images/integrations/logos/apester.png" />
    </div>

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

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

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

    <BadgeRowCenter label="Capability">
      <BadgeContainer>
        <CapabilityBadge capability="Event Collection" />
      </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' }}>
    Apester enables publishers to collect first-party survey data through multiple-choice surveys on their website.
  </p>
</Card>

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

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

## Overview

Apester allows you to run multiple-choice surveys on your site. This declared first-party data can be useful in building cohorts, whether for demographics or purchase intent.

Unlike other survey platform integrations where you enable the integration from within the survey platform, Apester requires you to deploy custom JavaScript code on your website to enable the integration. You cannot initiate this integration from within the Apester platform.

Use cases include:

* Build cohorts based on survey responses (e.g., demographic segments, purchase intent)
* Track survey question-level responses for advanced segmentation
* Create audiences based on specific answer patterns

## Environment Compatibility

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

## Prerequisites

* **Permutive SDK Deployment**: The Permutive JavaScript SDK must be deployed on your website where Apester surveys will run.
* **Custom ApesterSurveyResponse Event**: Contact your Permutive Customer Success Manager (CSM) to request the setup of the `ApesterSurveyResponse` custom event on your workspace. This event must be preconfigured before you can use the integration.
* **Access to Both Platforms**: You need access to both your website codebase (to deploy the JavaScript code) and the Apester platform (to create and manage surveys).
* **Developer Resources**: You will need developer support to add the integration code to your website.
* **Verify with your CSM**: Confirm that this collector is part of your Permutive plan.

## Setup

<Tabs>
  <Tab title="Primary Setup Steps">
    <Steps>
      <Step title="Request Custom Event Configuration">
        Contact your Permutive Customer Success Manager (CSM) to request the setup of the `ApesterSurveyResponse` custom event in your workspace. This step must be completed before proceeding with the code deployment.
      </Step>

      <Step title="Deploy Integration Code">
        Add the following JavaScript code to your website where Apester surveys are displayed. This code listens for survey responses and sends them to Permutive as `ApesterSurveyResponse` events.

        ```javascript theme={"dark"}
        window.addEventListener('message', (event) => {
          if (event && event.data && event.data.type === 'picked_answer') {
            var permutiveEventContent = {};
            [
              'interactionId',
              'interactionIndex',
              'interactionTitle',
              'answerId',
              'answerText',
              'slideId',
              'slideTitle',
              'externalId',
            ].forEach(function(property) {
              if (!event.data.data.hasOwnProperty(property) ||
                  !event.data.data[property]) {
                return;
              }
              permutiveEventContent[property] = event.data.data[property] + '';
            });

            window.permutive.track('ApesterSurveyResponse', permutiveEventContent);
          }
        });
        ```

        <Warning>
          This code is provided "as is", without warranty of any kind, express or implied. In no event shall Permutive be liable for any claim, damages, updates, or other liability.
        </Warning>

        Ensure this code is placed on all pages where Apester surveys will be displayed and that it loads after the Permutive SDK.
      </Step>

      <Step title="Verify Event Collection">
        After deploying the integration code, run a test survey and submit responses. In your Permutive dashboard, navigate to the Events page and verify that `ApesterSurveyResponse` events are being collected. You should see recent events appearing in the Events list with the survey response data.
      </Step>

      <Step title="Build Survey-Based Cohorts">
        Once event collection is verified, you can build cohorts based on survey responses. In the Permutive cohort builder, the `ApesterSurveyResponse` event will appear in the event dropdown list.

        A common use case is to build a cohort of users who have answered a question in a certain way. For example, you can create cohorts for:

        * Users whose gender is "female"
        * Users interested in specific products or categories
        * Users who completed a particular survey
        * Demographic segments based on age, location, or other attributes
      </Step>
    </Steps>
  </Tab>

  <Tab title="Web">
    The integration code provided in the Primary Setup Steps is specifically for Web environments. No additional web-specific configuration is required beyond deploying the code snippet and ensuring the Permutive SDK is present on the page.

    The code uses the browser's `window.addEventListener` API to listen for Apester survey response messages and forwards them to Permutive via the `window.permutive.track()` method.
  </Tab>
</Tabs>

## Data Types

With your Apester integration setup, you'll see the following event type collected in Permutive:

<AccordionGroup>
  <Accordion title="ApesterSurveyResponse">
    This event is triggered when a user responds to an Apester survey question. The event captures details about the survey interaction, question, and answer provided.

    <ResponseField name="interactionId" type="string">
      The Apester interaction ID. Example: `5cb48901b712a358aeb0180b`
    </ResponseField>

    <ResponseField name="interactionIndex" type="string">
      The interaction index.
    </ResponseField>

    <ResponseField name="interactionTitle" type="string">
      Title is taken from the first text element on the first slide. Example: `My great story`
    </ResponseField>

    <ResponseField name="answerId" type="string">
      The answer ID. Example: `19174477-5b29-4044-b5bf-b683024aa420`
    </ResponseField>

    <ResponseField name="answerText" type="string">
      Text of the answer provided by the user. Example: `definitely gonna buy the new iPhone`
    </ResponseField>

    <ResponseField name="slideId" type="string">
      The question ID. Example: `5cb48901b712a35acbb0180a`
    </ResponseField>

    <ResponseField name="slideTitle" type="string">
      Text of the question. Example: `What do you think of the new iPhone?`
    </ResponseField>

    <ResponseField name="externalId" type="string">
      The external ID is taken from the external-id attribute on the embedded element. Example: `9864`
    </ResponseField>

    <Note>
      ApesterSurveyResponse events will also contain default Permutive event properties such as page URL (`client.url`) and page title (`client.title`).
    </Note>
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="ApesterSurveyResponse events are not appearing in Permutive">
    Verify the following:

    * The custom `ApesterSurveyResponse` event has been configured in your Permutive workspace. Contact your CSM if this step was missed.
    * The integration code has been deployed to all pages where Apester surveys are displayed.
    * The Permutive SDK is deployed and loading correctly on those pages. Use the Permutive Chrome Extension to verify SDK presence.
    * The integration code is loading after the Permutive SDK (check that `window.permutive` is available).
    * Check your browser's developer console for any JavaScript errors that might prevent the code from executing.
  </Accordion>

  <Accordion title="Custom event not configured in workspace">
    The `ApesterSurveyResponse` event is a custom event that must be preconfigured by Permutive before the integration will work. If you deploy the integration code without this custom event being set up first, survey data will not be collected.

    Contact your Customer Success Manager to request the custom event setup.
  </Accordion>

  <Accordion title="Integration code is not capturing survey responses">
    If the integration code is deployed but not capturing responses:

    * Verify that Apester surveys are actually loading on the page and users are submitting responses.
    * Check that the message event data structure matches what the code expects (type: 'picked\_answer').
    * Use your browser's developer console to monitor message events and verify that Apester is sending the expected data structure.
    * Ensure the `window.permutive.track()` method is available when the code executes.
  </Accordion>

  <Accordion title="Some survey response fields are missing">
    The integration code only captures fields that are present in the Apester message data. If certain fields like `interactionIndex` or `externalId` are not populated by Apester, they will not be included in the Permutive event.

    This is expected behavior. The code checks if each field exists and has a value before including it in the event data. Not all Apester survey configurations will populate all available fields.
  </Accordion>

  <Accordion title="Need help or have questions?">
    For questions about this integration, contact [Technical Services](mailto:technical-services@permutive.com).
  </Accordion>
</AccordionGroup>

## Changelog

<Info>
  For the latest updates and changes to this integration, visit [changelog.permutive.com](https://changelog.permutive.com).
</Info>
