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

# TextRazor

> Integrate with TextRazor for contextual data enrichment.

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/textrazor.png?fit=max&auto=format&n=tY6HQAw8J0a8II15&q=85&s=ecb7a631f24076dcb08ff63f8a25cdb0" alt="TextRazor" style={{ maxWidth: '32px', maxHeight: '32px', display: 'block' }} width="292" height="284" data-path="images/integrations/logos/textrazor.png" />
    </div>

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

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

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

        <EnvironmentBadge environment="iOS" />

        <EnvironmentBadge environment="Android" />
      </BadgeContainer>
    </BadgeRowCenter>

    <BadgeRowCenter label="Capability">
      <BadgeContainer>
        <CapabilityBadge capability="Contextual Signal" />
      </BadgeContainer>
    </BadgeRowCenter>

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

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

        <ProductRequiredBadge product="Contextual" />
      </BadgeContainer>
    </BadgeRowCenter>
  </div>

  <p style={{ margin: 0, fontSize: '0.875rem', color: '#6b7280', lineHeight: '1.5' }}>
    TextRazor provides advanced text analytics and content classification using natural language processing and machine learning.
  </p>
</Card>

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

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

## Overview

TextRazor provides advanced text analytics and content classification using natural language processing and machine learning. It extracts entities, concepts and categories from unstructured text, enabling precise content understanding and contextual targeting. The integration enriches your `Pageview` events with contextual classifications using the IAB 3.0 taxonomy, enabling you to build contextual cohorts without relying on user identifiers. TextRazor classifies content into Categories, Entities, and Concepts, enabling precise contextual targeting without user data.

This integration is a Source:

* **Source:** Permutive enriches `Pageview` events with contextual classifications from TextRazor.

Use cases include:

* Build contextual cohorts using IAB 3.0 category classifications for cookie-less targeting
* Apply brand safety rules by including or excluding specific categories
* Power privacy-safe targeting strategies across your inventory
* Leverage entity and concept extraction for advanced content understanding
* Enable precise audience targeting based on contextual intelligence

## Environment Compatibility

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

## Prerequisites

* **Permutive SDK**: Deployed on your web and mobile properties where you want content classified.
* **Permutive enablement**: TextRazor must be enabled for your workspace by Permutive.
* **Accessible content**: Content should be accessible to classifiers. For paywalled or bot-protected pages, configure an allow mechanism (see Setup).
* **Monthly classification quota**: Ensure your monthly classification quota covers expected volume.

<Expandable title="Advanced: Paywalls and bot checks">
  Some sites block non-user traffic. If classifiers cannot fetch content, you
  can configure a URL parameter in **Contextual > Catalog > Settings** that will be appended to classification requests. Configure your paywall to allow bypass when this parameter is present. The standard parameter is `bot-access=true`, though custom parameter names and values can be configured.
</Expandable>

## Setup

<Steps>
  <Step title="Enable TextRazor">
    There are two ways to enable TextRazor:

    * **Permutive-managed**: If TextRazor is included in your Permutive contract, contact your Customer Success Manager (CSM) to enable it for your workspace.
    * **Your own credentials**: If you have a direct relationship with TextRazor, work with your CSM to configure the integration using your own API key.
  </Step>

  <Step title="Configure classification settings">
    In the Permutive dashboard, navigate to **Contextual > Catalog** and locate TextRazor. Configure your settings including:

    * **Requested Types**: Specify which classification types to request (Categories, Entities, and/or Concepts for TextRazor)
    * **Domains**: Restrict classifications to specific domains to optimize quota usage. The domains shown are based on what you have defined under **Settings > Domains & App names**
    * **Quota**: Maximum monthly classification quota. You can only change this value when using your own credentials; otherwise it is managed by Permutive. Once the quota is reached, no more content will be classified until the next month
    * **Selective Classifications Threshold**: Set a minimum traffic threshold to classify only high-traffic URLs, optimizing quota usage. The default threshold is **20 pageviews within 24 hours** before initial classification is triggered

    If you are using your own credentials, you will also configure:

    * **API Key**: Your TextRazor API key for authentication
  </Step>

  <Step title="(Optional) Configure access for paywalled content">
    If your site uses a paywall or bot mitigation that blocks classifier requests, configure an allow mechanism. Navigate to **Contextual > Catalog > Settings** and configure a URL parameter (e.g., `bot-access=true`) that will be appended to classification requests. Configure your paywall to allow bypass when this parameter is present.
  </Step>

  <Step title="Verify enrichment">
    After enablement, browse several article pages and check in your Permutive dashboard that `Pageview` events contain TextRazor classifications. Remember that pages must meet the configured threshold before they are classified. You can preview classifications by hovering over the TextRazor tile in the Catalog and clicking "Preview".
  </Step>
</Steps>

## Data Types

With TextRazor enabled, Permutive enriches your `Pageview` events with contextual classifications. Permutive automatically updates your event schema to include these properties.

<AccordionGroup>
  <Accordion title="Pageview">
    TextRazor enriches `Pageview` events with category, entity, and concept classifications.

    <ResponseField name="contextual.classifications.categories" type="list[object]">
      List of category classifications detected for the page. Each object contains:

      * `provider` (string, required): "textrazor"
      * `value` (string, required): The classification category ID. The dashboard uses the taxonomy to display human-readable names
      * `taxonomy` (string, required): "iab\_3\_0"
      * `confidence` (float, required): Confidence score for the classification
    </ResponseField>

    <ResponseField name="contextual.classifications.entities" type="list[object]">
      List of entity classifications detected for the page. Each object contains:

      * `provider` (string, required): "textrazor"
      * `value` (string, required): The entity name
      * `confidence` (float, required): Confidence score for the entity extraction
    </ResponseField>

    <ResponseField name="contextual.classifications.concepts" type="list[object]">
      List of concept classifications detected for the page. Each object contains:

      * `provider` (string, required): "textrazor"
      * `value` (string, required): The concept name
      * `confidence` (float, required): Confidence score for the concept extraction
    </ResponseField>
  </Accordion>
</AccordionGroup>

## Troubleshooting

<AccordionGroup>
  <Accordion title="Page not classified (no labels present)">
    Confirm the URL has met the minimum traffic threshold for classification.
    The default threshold is **20 pageviews within 24 hours**. Low-traffic or newly published pages may classify later. Contact Permutive Support to check if a specific URL has been classified or to verify your threshold configuration.
  </Accordion>

  <Accordion title="Monthly classification quota reached">
    If your monthly quota is reached, new URLs will not be classified until the next
    month. Contact your Customer Success Manager to review quotas.
  </Accordion>

  <Accordion title="Paywall or bot protection blocking classification">
    Classifier requests must be able to fetch the full article content. Configure your paywall to allow bypass using a URL parameter (e.g., `bot-access=true`). Set this in the Permutive dashboard under Contextual > Catalog > Settings, then configure your paywall system to allow access when this parameter is present in the URL.
  </Accordion>

  <Accordion title="Preview not showing classifications">
    If the Preview feature in the Contextual Catalog is not returning classifications, verify that the URL is publicly accessible and not blocked by bot protection. The Preview feature uses the same classification process as production, so access issues will prevent preview from working.
  </Accordion>

  <Accordion title="Authentication issues with custom credentials">
    If you are using your own TextRazor API key and experiencing authentication failures, verify that your API key is correctly configured. Contact your Customer Success Manager and TextRazor support to validate your credentials.
  </Accordion>
</AccordionGroup>

## Changelog

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