# Listing Risk Screen - brand and policy risk before you publish (`jev-tools/listing-risk-screen`) Actor

Screens marketplace listing text against your own watchlist and flags trademark variants, counterfeit positioning, copyrighted characters, prohibited claims and restricted categories. Catches the misspellings and letter swaps a keyword search cannot. Pay only for listings it actually screened.

- **URL**: https://apify.com/jev-tools/listing-risk-screen.md
- **Developed by:** [Deric Rifqi](https://apify.com/jev-tools) (community)
- **Categories:** E-commerce, AI
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$5.00 / 1,000 listing screeneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Listing Risk Screen — catch brand and policy risk before you publish

A takedown costs you the listing, the inventory behind it, and often the account.
This reads your listing **text** against your own watchlist and tells you what to
fix first:

| | |
| --- | --- |
| **verdict** | `clear` · `review` · `block` — an action, not a finding |
| **reason** | one label: `trademark_variant`, `counterfeit_positioning`, `copyrighted_character`, `prohibited_claim`, `restricted_category`, `unsubstantiated_claim`, `compatibility_reference`, `thin_listing`, `no_signal` |
| **near\_matches** | which watchlisted names were found in the text, and where to look |
| **signals** | the per-signal probabilities behind the verdict, so you can re-threshold without paying again |

Point it at any dataset — an Amazon or Shopify scraper, a supplier feed, your own
CSV of drafts — paste in your watchlist, and run it.

### The whole point: the spellings a keyword search cannot find

A `CONTAINS "Nike"` rule is free and you already have it. It also finds nothing
when the listing says something else. On a 260-listing corpus where every brand
was disguised, a plain substring search over the watchlist scored:

```
accuracy 0.835   recall 0.660   precision 0.849
```

That is the bar. Every one of these was read correctly as the brand, and none of
them contains the brand as text:

| in the listing | read as |
| --- | --- |
| `Niike` | Nike |
| `A1rP0ds` | AirPods |
| `J-B-L` | JBL |
| `Dys on` | Dyson |
| `Dyosn` | Dyson |
| `Aplpe` | Apple |
| `IuIuI3mon` | Lululemon |

### And the opposite mistake, which costs you just as much

Flagging everything is not screening. A watchlisted word used as ordinary
English is not a brand use, and **none of these was blocked**:

| in the listing | verdict |
| --- | --- |
| "apple-shaped silicone charm, moulded to look like the fruit" | `clear` |
| "designed in-house by our founder, **Stanley** Okafor" | `clear` |
| "named after the physicist Freeman **Dyson**" | `clear` |
| "you will marvel at how little room this takes in a bag" | `review` |
| "tough enough to take down to the **barbie** for an afternoon" | `review` |

The last two are the honest limit: a word that is both a brand and ordinary
English gets held for you to glance at rather than cleared outright. Eight of
the sixty clean listings in the test corpus land in `review` for exactly this
reason. None of them is blocked, and none needs a rewrite — it costs you a look.

It also separates a legitimate compatibility reference — "a case **for** AirPods
Pro, not made by Apple" — from a listing claiming to **be** the brand. The first
goes to `review` so you can check your wording once; only the second is blocked.

### What was measured

260 labelled listings, thirteen adversarial case families:

| | |
| --- | --- |
| Verdict accuracy, three buckets | **0.931** |
| **Infringing listings wrongly cleared** | **0** |
| **Clean listings wrongly blocked** | **0** |
| **Unreadable listings wrongly cleared** | **0** |
| Clean listings sent to `review` needlessly | 13 of 60 |

Nine of the thirteen families are perfect: exact brand use, counterfeit
positioning, copyrighted characters, prohibited claims, restricted categories,
thin listings and multi-signal combinations all 20/20.

The mistakes it does make go one step in the cautious direction — into `review`,
where you look at it. That is deliberate: a needless review costs two minutes and
a missed infringement costs the account.

### What it does not do

**This screens text. It is a risk signal, not a legal opinion and not a
clearance.** Design-patent and image rights live in the product photo and are not
screened at all — a listing marked `clear` here has not been cleared of those.
Every output row carries that disclaimer, because a report that reads as legal
advice is worse than no report.

Two limits worth knowing before you buy:

- **Three-letter brands are hard.** A one-character swap on a short name is
  surfaced as a near match, so the listing goes to `review`, but it may not be
  read as the brand itself.
- **A variant written in lowercase** is not surfaced as a near match. Exact
  matches are found in any casing.

### Billing

You are charged per listing **screened** — never per listing returned, and never
for one it failed to judge. Those come back in the dataset marked
`billed: false` with the error on the row, so nothing vanishes silently.

Before any work starts, the run is capped by your own charge limit, so it cannot
bill its way into a wall halfway through and hand you a half-screened
catalogue. If more than a fifth of the calls fail, the run **fails** rather than
returning a report whose gaps read as clean.

### Input

`screenPolicy` is required and is the whole product:

```json
{
  "own_brands": ["Your Brand"],
  "watchlist": {
    "brands": ["Apple", "AirPods", "Anker", "Nike", "Dyson"],
    "franchises": ["Disney", "Mickey Mouse", "Pokemon"],
    "prohibited_terms": ["FDA approved", "cures", "100% safe", "best seller"]
  },
  "restricted_categories": ["lithium batteries", "supplements", "cosmetics"]
}
```

`own_brands` are yours and are never flagged. A name that is not on the list is a
name nobody looks for, so put your real competitors and the franchises your
category attracts on it.

# Actor input Schema

## `screenPolicy` (type: `object`):

Your own watchlist. own\_brands are yours and are never flagged. watchlist.brands and watchlist.franchises are the names you must not be seen using. watchlist.prohibited\_terms are claims your marketplace forbids outright. restricted\_categories are the product types that need approval or a certificate before listing. Every field is optional, but a name that is not on the list is a name nobody looks for.

## `sourceDatasetId` (type: `string`):

The dataset ID of any scraper run whose items you want screened. Leave empty and paste records into 'listings' instead.

## `listings` (type: `array`):

Records to screen, if you are not reading them from a dataset. Any shape is accepted. The fields read as listing text are title, brand, bullets and description; everything else is carried through to the output untouched.

## `idField` (type: `string`):

Falls back to the row number when the field is missing.

## `maxItems` (type: `integer`):

A hard ceiling on how many listings get screened, and therefore on what this run can cost you.

## `keepVerdicts` (type: `array`):

Everything is screened and billed; this only decides what lands in the output dataset. The default returns all three, because a cleared listing missing from the report is indistinguishable from one that was never screened.

## `concurrency` (type: `integer`):

Parallel judgements. 12 screens about 13 listings a second.

## `includeAnswers` (type: `boolean`):

Adds the calibrated signal probabilities to every row, so you can re-threshold the results yourself without paying again.

## Actor input object example

```json
{
  "screenPolicy": {
    "platform": "Amazon US",
    "category": "consumer electronics accessories",
    "own_brands": [
      "Your Brand"
    ],
    "watchlist": {
      "brands": [
        "Apple",
        "AirPods",
        "Anker",
        "Bose",
        "Sony",
        "Samsung",
        "Nike",
        "Dyson",
        "Stanley"
      ],
      "franchises": [
        "Disney",
        "Mickey Mouse",
        "Marvel",
        "Pokemon",
        "Hello Kitty",
        "Star Wars"
      ],
      "prohibited_terms": [
        "FDA approved",
        "cures",
        "treats",
        "medical grade",
        "100% safe",
        "best seller",
        "#1 on Amazon",
        "military grade"
      ]
    },
    "restricted_categories": [
      "lithium batteries",
      "supplements",
      "cosmetics",
      "medical devices",
      "children's toys under 3"
    ]
  },
  "listings": [
    {
      "id": "1",
      "title": "Your Brand silicone case for AirPods Pro",
      "brand": "Your Brand",
      "bullets": [
        "Compatible with AirPods Pro",
        "Soft-touch finish"
      ],
      "description": "A Your Brand case. Fits AirPods Pro. Not made by Apple."
    }
  ],
  "idField": "id",
  "maxItems": 1000,
  "keepVerdicts": [
    "clear",
    "review",
    "block"
  ],
  "concurrency": 12,
  "includeAnswers": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "screenPolicy": {
        "platform": "Amazon US",
        "category": "consumer electronics accessories",
        "own_brands": [
            "Your Brand"
        ],
        "watchlist": {
            "brands": [
                "Apple",
                "AirPods",
                "Anker",
                "Bose",
                "Sony",
                "Samsung",
                "Nike",
                "Dyson",
                "Stanley"
            ],
            "franchises": [
                "Disney",
                "Mickey Mouse",
                "Marvel",
                "Pokemon",
                "Hello Kitty",
                "Star Wars"
            ],
            "prohibited_terms": [
                "FDA approved",
                "cures",
                "treats",
                "medical grade",
                "100% safe",
                "best seller",
                "#1 on Amazon",
                "military grade"
            ]
        },
        "restricted_categories": [
            "lithium batteries",
            "supplements",
            "cosmetics",
            "medical devices",
            "children's toys under 3"
        ]
    },
    "listings": [
        {
            "id": "1",
            "title": "Your Brand silicone case for AirPods Pro",
            "brand": "Your Brand",
            "bullets": [
                "Compatible with AirPods Pro",
                "Soft-touch finish"
            ],
            "description": "A Your Brand case. Fits AirPods Pro. Not made by Apple."
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jev-tools/listing-risk-screen").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "screenPolicy": {
        "platform": "Amazon US",
        "category": "consumer electronics accessories",
        "own_brands": ["Your Brand"],
        "watchlist": {
            "brands": [
                "Apple",
                "AirPods",
                "Anker",
                "Bose",
                "Sony",
                "Samsung",
                "Nike",
                "Dyson",
                "Stanley",
            ],
            "franchises": [
                "Disney",
                "Mickey Mouse",
                "Marvel",
                "Pokemon",
                "Hello Kitty",
                "Star Wars",
            ],
            "prohibited_terms": [
                "FDA approved",
                "cures",
                "treats",
                "medical grade",
                "100% safe",
                "best seller",
                "#1 on Amazon",
                "military grade",
            ],
        },
        "restricted_categories": [
            "lithium batteries",
            "supplements",
            "cosmetics",
            "medical devices",
            "children's toys under 3",
        ],
    },
    "listings": [{
            "id": "1",
            "title": "Your Brand silicone case for AirPods Pro",
            "brand": "Your Brand",
            "bullets": [
                "Compatible with AirPods Pro",
                "Soft-touch finish",
            ],
            "description": "A Your Brand case. Fits AirPods Pro. Not made by Apple.",
        }],
}

# Run the Actor and wait for it to finish
run = client.actor("jev-tools/listing-risk-screen").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "screenPolicy": {
    "platform": "Amazon US",
    "category": "consumer electronics accessories",
    "own_brands": [
      "Your Brand"
    ],
    "watchlist": {
      "brands": [
        "Apple",
        "AirPods",
        "Anker",
        "Bose",
        "Sony",
        "Samsung",
        "Nike",
        "Dyson",
        "Stanley"
      ],
      "franchises": [
        "Disney",
        "Mickey Mouse",
        "Marvel",
        "Pokemon",
        "Hello Kitty",
        "Star Wars"
      ],
      "prohibited_terms": [
        "FDA approved",
        "cures",
        "treats",
        "medical grade",
        "100% safe",
        "best seller",
        "#1 on Amazon",
        "military grade"
      ]
    },
    "restricted_categories": [
      "lithium batteries",
      "supplements",
      "cosmetics",
      "medical devices",
      "children'\''s toys under 3"
    ]
  },
  "listings": [
    {
      "id": "1",
      "title": "Your Brand silicone case for AirPods Pro",
      "brand": "Your Brand",
      "bullets": [
        "Compatible with AirPods Pro",
        "Soft-touch finish"
      ],
      "description": "A Your Brand case. Fits AirPods Pro. Not made by Apple."
    }
  ]
}' |
apify call jev-tools/listing-risk-screen --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jev-tools/listing-risk-screen"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/47mjJ6o8HsC3MIl24/builds/DTFn24U65dhafbtz5/openapi.json
