# EUIPO & Benelux Trademark Search & Watch (TMview) (`olliolli/eu-trademark-watch`) Actor

Find similar trademark names across EUIPO and Benelux via TMview. Compare spelling, sound and Nice classes; track new filings, status changes and available opposition deadlines. Export results or send webhook alerts. Optional official EUIPO API access.

- **URL**: https://apify.com/olliolli/eu-trademark-watch.md
- **Developed by:** [Tom J](https://apify.com/olliolli) (community)
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $30.00 / 1,000 mark checkeds

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

> **Screening aid, not legal advice.** Always confirm a filing and its deadline in the official register before you act.

Search **EUIPO and Benelux (BOIP) trademarks via TMview** for names that look or sound like yours. Every similar filing gets a **similarity score from 0 to 100 with plain-language reasons**, shared Nice classes, its status and the **opposition deadline**. In **watch** mode the Actor remembers what it already reported and returns only **new filings and status changes**, so a weekly schedule becomes a trademark watch service. No login, no API key needed. From **$30 per 1,000 mark checks**.

### What you can do with it

- **Run a trademark watch**: check your marks (or your clients' marks) every week and get only new similar filings and status changes.
- **Do a brand clearance scan**: before you launch a name, see every similar mark across all statuses and dates.
- **Never miss an opposition window**: each hit shows the opposition deadline and the days left.
- **Serve IP clients**: keep one watch list per client with **State name**, add notes per mark, and send results by e-mail or webhook.
- **Skip your own filings**: ignore your own applicant names.

### How to run a trademark watch in 3 steps

1. **Add your marks** (up to 500), optionally with a note per mark (for example "client A") and Nice classes.
2. **Run once in `baseline` mode**: it reports every similar filing of the last 365 days and sets the starting point.
3. **Schedule a weekly run in `watch` mode** (Schedules → weekly). Add Apify's **Send email** integration or a **webhook URL** to get notified.

### Modes

| Mode | Returns | Memory |
|---|---|---|
| `watch` (default) | Only **new filings** (`NEW_FILING`) and **status changes** (`STATUS_CHANGE`, e.g. published → under opposition → registered) since the previous run | Remembers per mark |
| `baseline` | Every similar filing of the last 365 days (`MATCH`); sets the starting point for watch runs | Overwrites memory |
| `clearance` | One-off similarity scan over every status and date (`MATCH`) | No memory |

A first watch run without a baseline reports everything similar in the look-back window as new. Adding or removing marks does not reset the others. Use a different **State name** for each independent list, and avoid overlapping runs for the same list.

### Input

| Setting | Meaning | Default |
|---|---|---|
| Marks | Names to watch (max 500 per run), with optional note and Nice classes | — |
| Mode | `watch`, `baseline`, `clearance` | `watch` |
| State name | Separates watch lists | — |
| Threshold | Only filings scoring at or above it are returned | 70 |
| Nice class mode | `same` (−35 without a shared class), `related` (−25 without a related class), `any` (no malus) | — |
| Look back | Days for baseline | 365 |
| Ignore applicants | Skip filings of these applicants (e.g. your own) | — |
| Source | TMview (default) or the official EUIPO Trademark Search API | TMview |
| Webhook URL | One POST per run with new hits and status changes | — |

### Output

Two dataset views: **New filings to review** (mark, similarity, office, classes, deadline, link) and **All matches** (every field).

```json
{
  "watchedMark": "Aurava",
  "watchedNotes": "client A",
  "eventType": "NEW_FILING",
  "office": "BX",
  "applicationNumber": "1799991",
  "markName": "AURAVIE",
  "markFeature": "WORD",
  "similarity": 98,
  "similarityReasons": [
    "Sounds the same: AURAVA / AURAVIE (same Soundex code)",
    "Spelled similarly: AURAVA / AURAVIE (91% letter match)",
    "Classes 3, 35 shared"
  ],
  "niceClasses": [3, 35],
  "sharedClasses": [3, 35],
  "status": "PUBLISHED",
  "applicationDate": "2026-10-02",
  "publicationDate": "2026-10-21",
  "oppositionDeadline": "2026-12-21",
  "oppositionDaysLeft": 58,
  "oppositionNote": "Opposition period as published in the register",
  "applicants": ["Example Cosmetics BV"],
  "registerUrl": "https://www.tmdn.org/tmview/…",
  "source": "TMview (EUIPN)",
  "checkedAt": "2026-10-24T06:00:00Z"
}
```

*Example values for illustration.* The run summary (`OUTPUT`) shows marks checked, requests, `stopped`, `uncheckedMarks`, `connectionAttempts` and `recoveryEvents`. Check those fields, not only the green run status. A watch run with zero new hits is a valid result. `billing` compares completed checks and delivered rows with the SDK event counters; a mismatch produces a warning. Its expected custom-event list price excludes the platform start event and is not an invoice or a platform-cost estimate. Developer monitoring separately compares the final Apify event counters. Repeated check and residential charge requests use operation keys; these do not guarantee recovery across arbitrary restarts.

### How the similarity score works

Names are compared after ignoring case, accents, spaces, hyphens and punctuation:

- **Spelling**: Jaro-Winkler, penalised when lengths differ a lot.
- **Sound**: Double Metaphone and Soundex codes.
- **Words**: your mark inside a longer mark, shared words.
- **Nice classes**: +5 for a shared class; a malus without a shared or related class (see Nice class mode). Related classes use practical groups (e.g. 9, 35, 38, 42), not a legal test.

Identical names score 100. Logos and figurative marks without Latin-letter words get no score.

### How the opposition deadline is calculated

The register's own opposition period is used when it is published. Otherwise:

- **EU trade mark application**: 3 months from publication.
- **International registration designating the EU**: 3 months, starting 1 month after EUIPO republication (Art. 196(2) EUTMR).
- **Benelux application**: 2 months from publication.

If neither is possible, the deadline is empty and `oppositionNote` explains why. Office closing days are not taken into account.

### How much does trademark watching cost?

| Event | Price |
|---|---|
| Actor start (per run, at 1 GB) | $0.02 |
| Mark checked (watch or clearance) | $0.03 |
| Baseline mark | $0.05 |
| Similar filing (per delivered row) | $0.005 |
| Residential session (once per run, only when the residential route completes a mark) | $0.05 |
| Residential proxy (per mark completed over residential) | $0.002 |

**Examples:** one clearance check that returns 2 similar filings: $0.02 + $0.03 + 2 × $0.005 = **$0.06**. Twenty marks watched weekly: about **$0.62 per run** + $0.005 per new row (+ $0.09 if a run needs the residential route). The Pricing tab is authoritative.

#### What you are not charged for

- Marks that could not be checked completely (no mark or baseline fee).
- Filings below your threshold, and unchanged filings already delivered earlier.
- Rows that were not delivered, and failed webhooks.
- The residential session when no mark was completed over residential.

The small start fee applies to every run, including a run that fails.

### Connection and the residential proxy surcharge

The Actor opens the public TMview app in a fresh browser session, reused across marks. At most **three connection attempts per run**: the Apify datacenter proxy, then residential (if allowed), then a new residential session. Cookies are never copied between attempts. HTTP 429 stops the run without switching IPs. No user cookies, logins, captcha solvers or unbounded IP rotation are used.

### Official EUIPO API (optional)

Choose **Official EUIPO Trademark Search API**, register a free app on dev.euipo.europa.eu, subscribe it to "Trademark search" and paste the client ID and secret (stored encrypted). The API covers EU marks and international registrations designating the EU only, not Benelux or national marks.

### Integrate with any app

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("olliolli/eu-trademark-watch").call(run_input={...})  # see the Input tab (JSON)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(row["markName"], row["similarity"], row["oppositionDeadline"])
```

The webhook sends one POST per run with `runId`, `datasetId`, `mode`, `marksChecked`, `newHits` and `statusChanges`, ready for Make, Zapier, n8n or Slack. Through Apify's **MCP** server, AI assistants can run a clearance check as a tool.

### Privacy

Applicants and representatives appear **by name only, as the register publishes them**. Addresses, e-mail addresses and phone numbers are never copied. Watch memory and a 24-hour detail cache stay in your own Apify account and can be deleted at any time.

### Good to know

- Live validation covers **EUIPO (EM)** and **Benelux (BX)** via TMview. Other office filters and the API mode have not had the same live validation.
- At most 200 TMview candidates per mark; up to 25 older open filings are rechecked per mark per run.
- Names in other scripts (Greek, Cyrillic) are not transliterated.

### FAQ

**Does it cover Benelux (BOIP) trademarks?** Yes, through TMview, including the 2-month Benelux opposition period.

**What does a similarity score of 80 mean?** That spelling, sound, words and classes together are close. The reasons are listed with every hit; a lawyer decides on likelihood of confusion.

**Can I watch trademarks for several clients?** Yes: one State name per client, and a note per mark.

**How do I get e-mail alerts for new similar trademarks?** Schedule weekly `watch` runs and add Apify's Send email integration, or use the webhook.

**Why did my run use a residential proxy?** TMview sometimes refuses datacenter connections. The Actor then switches (at most three attempts per run) and charges the residential events only if a mark was completed that way.

**Is this legal advice?** No. It is a screening aid. Confirm every filing and deadline in the official register.

### Disclaimer

Independent tool, **not affiliated with, endorsed by or sponsored by EUIPO, the EUIPN, BOIP or WIPO**. TMview and the EUIPO API have their own terms of use; you are responsible for your use of the data.

### Need help?

Open an issue on the **Issues** tab.

# Actor input Schema

## `watchlist` (type: `array`):

Your marks, each with its Nice classes and an optional note (for example the client). Up to 500 marks per run. Example: \[{"mark": "Lumora", "niceClasses": \[9, 42], "notes": "client A"}]. Without classes, classes are not compared.

## `mode` (type: `string`):

Schedule "watch" weekly. Optional: one "baseline" run first, so that watch runs only report what is new after it. Use "clearance" to check a name once.

## `lookbackDays` (type: `integer`):

Only filings with an application date in the last N days. Empty: 14 days in watch mode, 365 in baseline mode, all dates in clearance mode. Previously reported filings are deduplicated. A longer window can increase compute and proxy usage.

## `source` (type: `string`):

TMview is the public search tool of the EU Intellectual Property Network. The official EUIPO API needs your own free API keys (fields below) and covers EU trade marks and international registrations designating the EU.

## `offices` (type: `array`):

Trade mark offices to search in TMview. Belgium, the Netherlands and Luxembourg are covered by BX. Ignored with the official EUIPO API.

## `proxyConfiguration` (type: `object`):

TMview uses at most three fresh browser/proxy sessions across the whole run. Default order: datacenter, residential, new residential session. A working session is reused across marks. Search/detail requests stay sequential at most once per second. Browser runs need 1024 MB. Completed checks over residential carry $0.002 per mark plus a one-time $0.05 residential-session event after the first completed check; the official EUIPO API uses no browser and never uses residential.

## `allowResidentialProxy` (type: `boolean`):

Allow residential fallback when the selected TMview connection fails, including a later timeout or session refusal. The total limit is three connection attempts per run. Off: retries stay on the selected connection type. If you explicitly select residential in Proxy, that selection still applies. Every completed mark checked over residential can carry the Residential proxy event; the $0.02 start fee per allocated GB applies even if all attempts fail. The $0.05 residential-session fee is charged once per run only after a completed residential check, plus $0.002 per completed residential mark. Platform compute and proxy usage are included in event prices for standard runs.

## `similarityThreshold` (type: `integer`):

Only filings that score at least this much are returned. The score combines spelling, sound and shared words, plus a bonus or malus for the Nice classes. Each result explains its score.

## `classMatch` (type: `string`):

Which classes count as a conflict. "Related" uses practical class groups, not a legal test.

## `statuses` (type: `array`):

Empty: filed, published, under opposition and registered in watch and baseline mode; every status in clearance mode. Status changes of filings you already received are always reported.

## `markFeatures` (type: `array`):

Empty: all types. Only the name of a mark is compared; images are not compared.

## `excludeApplicants` (type: `array`):

Your own company names (or a client's), so that your own new filings are not reported. Matches when the applicant name contains the text, case ignored.

## `webhookUrl` (type: `string`):

Optional. One POST per run with {runId, source, newHits, statusChanges}. A failed POST is only a warning. For e-mail, add Apify's "Send email" integration to the Actor or schedule.

## `stateName` (type: `string`):

Optional. Watch runs remember per mark what they already reported. Use a different name per independent watch list that contains the same marks (for example per client).

## `euipoClientId` (type: `string`):

Only for the source "Official EUIPO Trademark Search API". Register a free app on dev.euipo.europa.eu and subscribe it to the Trademark Search API. Stored encrypted; never written to the log or the results.

## `euipoClientSecret` (type: `string`):

The secret of that app. Stored encrypted; never written to the log or the results.

## `euipoEnvironment` (type: `string`):

Use the sandbox only to test keys from dev-sandbox.euipo.europa.eu.

## Actor input object example

```json
{
  "watchlist": [
    {
      "mark": "Lumora",
      "niceClasses": [
        3,
        35
      ],
      "notes": "Example only: replace with your own brand"
    }
  ],
  "mode": "clearance",
  "lookbackDays": 365,
  "source": "tmview",
  "offices": [
    "EM",
    "BX"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "allowResidentialProxy": true,
  "similarityThreshold": 70,
  "classMatch": "same",
  "euipoEnvironment": "production"
}
```

# Actor output Schema

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

One row per new filing, status change or match, with similarity, reasons and opposition deadline.

## `summary` (type: `string`):

Marks checked, rows, stop reason, requests and webhook result (OUTPUT).

# 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 = {
    "watchlist": [
        {
            "mark": "Lumora",
            "niceClasses": [
                3,
                35
            ],
            "notes": "Example only: replace with your own brand"
        }
    ],
    "mode": "clearance",
    "lookbackDays": 365,
    "offices": [
        "EM",
        "BX"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("olliolli/eu-trademark-watch").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 = {
    "watchlist": [{
            "mark": "Lumora",
            "niceClasses": [
                3,
                35,
            ],
            "notes": "Example only: replace with your own brand",
        }],
    "mode": "clearance",
    "lookbackDays": 365,
    "offices": [
        "EM",
        "BX",
    ],
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("olliolli/eu-trademark-watch").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 '{
  "watchlist": [
    {
      "mark": "Lumora",
      "niceClasses": [
        3,
        35
      ],
      "notes": "Example only: replace with your own brand"
    }
  ],
  "mode": "clearance",
  "lookbackDays": 365,
  "offices": [
    "EM",
    "BX"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call olliolli/eu-trademark-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,olliolli/eu-trademark-watch"
        }
    }
}
```

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/OMi8bE0xHwzzZkp2Q/builds/gHCIsecxHqNGlU3di/openapi.json
