# WIPO Madrid International Trademark Scraper (`scrapers_lat/wipo-madrid-trademarks-scraper`) Actor

Search 1.4M international trademark registrations: mark text, holder name and address, IP representative firm, designated countries, Nice classes, goods and services, refusals, oppositions and expiry dates. JSON, CSV, Excel.

- **URL**: https://apify.com/scrapers\_lat/wipo-madrid-trademarks-scraper.md
- **Developed by:** [Scrapers Lat](https://apify.com/scrapers_lat) (community)
- **Categories:** Lead generation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $12.75 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

[![WIPO Madrid International Trademark Scraper](https://scrapers.lat/banners/wipo-madrid-trademarks-scraper.png)](https://apify.com/scrapers_lat/wipo-madrid-trademarks-scraper)

## WIPO Madrid International Trademark Scraper

Here is one real result, with every field the actor returns:

```json
{
  "internationalRegistrationNumber": "1336632",
  "markText": "social sweethearts",
  "status": "ACT",
  "statusLabel": "In force",
  "registrationDate": "2016-12-31",
  "expiryDate": "2026-12-31",
  "monthsToExpiry": 4,
  "holderName": "social sweethearts GmbH",
  "holderAddress": "Karl-Valentin-Straße 17, 82031 Grünwald",
  "holderCountry": "DE",
  "representativeName": "Osborne Clarke",
  "representativeAddress": "Reeperbahn 1, 20359 Hamburg",
  "representativeCountry": "DE",
  "originOffice": "DE",
  "designatedCountries": [
    "AU",
    "EM",
    "IN",
    "JP",
    "NO",
    "US",
    "CH",
    "CN",
    "RU"
  ],
  "designatedCountriesCount": 9,
  "niceClasses": [
    9,
    35,
    38,
    41,
    42
  ],
  "niceClassCount": 5,
  "basicApplicationNumber": null,
  "basicRegistrationNumber": "30 2011 067 198",
  "hasContactEmailOnFile": true,
  "holderNationality": null,
  "holderLegalNature": "Limited Liability Company (GmbH), Germany",
  "goodsServices": "9: Electronic publications, downloadable. | 35: Publication of printed matter (including downloadable) for commercial purposes; advertising agencies; marketing; presentation of companies on the internet and other media; communication agencies, namely, advertising and public relations services; business consultancy and advisory services, namely, communication advisory firm services and media consul …",
  "goodsServicesClassCount": 5,
  "useRequirementCountries": [
    "IN",
    "US"
  ],
  "protectedCountries": [
    "CH",
    "CN",
    "EM",
    "JP",
    "NO"
  ],
  "protectedCountriesCount": 5,
  "refusedCountries": [
    "AU",
    "IN",
    "RU",
    "US"
  ],
  "refusedCountriesCount": 4,
  "opposedCountries": [
    "AU"
  ],
  "renewalCount": 0,
  "transactionCount": 23,
  "lastTransactionCode": "INNP",
  "lastTransactionDate": "2026-03-30",
  "basicApplicationCountry": null,
  "basicApplicationDate": null,
  "basicRegistrationCountry": "DE",
  "basicRegistrationDate": "2012-05-15",
  "languageOfApplication": "English",
  "gazetteNumber": "2017/11",
  "matchedQuery": "filters",
  "detailUrl": "https://www3.wipo.int/madrid/monitor/en/showData.jsp?ID=ROM.1336632",
  "source": "WIPO Madrid international trademark register",
  "observedAt": "2026-08-19T21:30:21.004Z"
}
```

The most complete WIPO Madrid trademark scraper available. Search the international trademark register (about 1.4 million registrations filed under the Madrid System, covering protection in 130+ territories from a single filing) and get the full public record for each mark, plus derived fields, and 14 filters to target exactly the registrations you need. Export as JSON, CSV or Excel.

**📥 [Input](https://apify.com/scrapers_lat/wipo-madrid-trademarks-scraper/input-schema) · 📤 [Output](https://apify.com/scrapers_lat/wipo-madrid-trademarks-scraper/output-schema) · 💰 [Pricing](https://apify.com/scrapers_lat/wipo-madrid-trademarks-scraper/pricing) · ▶️ [Examples](https://apify.com/scrapers_lat/wipo-madrid-trademarks-scraper/examples)**

![Apify](https://img.shields.io/badge/Platform-Apify-1CE1CE?logo=apify\&logoColor=white)
![Coverage](https://img.shields.io/badge/Coverage-130%2B%20territories-blue)
![Output](https://img.shields.io/badge/Output-JSON%20%7C%20CSV%20%7C%20Excel-orange)
![Billing](https://img.shields.io/badge/Billing-Pay%20per%20result-brightgreen)

### Table of contents

- [What it does](#what-it-does)
- [Quickstart](#quickstart)
- [Input reference](#input-reference)
- [Output reference](#output-reference)
- [Use cases](#use-cases)
- [Run via API and CLI](#run-via-api-and-cli)
- [Fetch results](#fetch-results)
- [Billing and limits](#billing-and-limits)
- [FAQ and troubleshooting](#faq-and-troubleshooting)

### What it does

Give it trademark words, owner names or registration numbers (or no search at all and just filters) and it returns the matching international registrations with the full public record attached: who owns the mark, which IP firm represents them, where protection was sought, where it was granted, where it was refused or opposed, what goods and services it covers, and when it expires.

Every search field accepts a **list**, so one run can cover many brands or many owners at once. Results are merged and de-duplicated across searches. Fields with no value in the source are returned as `null`, never guessed.

With enrichment on (the default) each registration is expanded from its full public record: goods and services wording per Nice class, holder legal nature and nationality, basic application and registration details, and the per-territory outcome (granted, refused, opposed) derived from the registration's own transaction ledger.

### Quickstart

Open the actor, paste this into the input, and press Run. It returns up to 100 German-owned marks in Nice class 9 that expire in Q4 2026.

```json
{
  "holderCountries": ["DE"],
  "niceClasses": ["9"],
  "expiringFrom": "2026-10-01",
  "expiringTo": "2026-12-31",
  "maxTrademarks": 100,
  "fetchDetails": true
}
```

Leave every search field empty to browse purely by filter (newest registrations first). All filters combine with AND; multi-value fields match any of the listed values.

### Input reference

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `maxTrademarks` | integer | no | `10` | Maximum registrations to collect. The register holds about 1.4 million; for large pulls narrow with the filters. |
| `brandNames` | string\[] | no | (empty) | One or more trademark words to search. Each entry runs as its own search; results are merged and de-duplicated. Wildcards supported, for example `nova*`. |
| `holderNames` | string\[] | no | (empty) | One or more owner names, for example `Nestle`, `Siemens`. Each entry runs as its own search. |
| `internationalRegNumbers` | string\[] | no | (empty) | Look up specific registrations by number, for example `1323866`. |
| `goodsServices` | string | no | (empty) | Keyword matched against the goods and services wording, for example `software`, `footwear`, `pharmaceutical`. |
| `status` | enum | no | `ACT` | Registration status: `ACT` (in force), `INA` (no longer in force), `PEND` (not yet in force), or `ALL`. |
| `niceClasses` | string\[] | no | (all) | Nice classification class numbers, for example `9`, `35`, `42`. |
| `holderCountries` | string\[] | no | (all) | Two-letter ISO country codes of the owner's address, for example `DE`, `US`, `CN`. |
| `originOffices` | string\[] | no | (all) | Two-letter codes of the office the registration originated from, for example `US`, `DE`, `EM` (EU). |
| `designatedCountries` | string\[] | no | (all) | Only return registrations seeking protection in these territories, for example `BR`, `MX`, `JP`. |
| `expiringFrom` | string | no | (empty) | Only return registrations that expire on or after this date (`YYYY-MM-DD`). |
| `expiringTo` | string | no | (empty) | Only return registrations that expire on or before this date (`YYYY-MM-DD`). |
| `registeredFrom` | string | no | (empty) | Only return registrations dated on or after this date (`YYYY-MM-DD`). |
| `registeredTo` | string | no | (empty) | Only return registrations dated on or before this date (`YYYY-MM-DD`). |
| `fetchDetails` | boolean | no | `true` | When on (recommended), enrich each registration with goods and services, legal nature, basic-filing details, refusals, oppositions and renewals. Turn off for a faster, lighter run. |

### Output reference

One dataset item per international registration. Types: `string`, `integer`, `boolean`, `string[]`, `integer[]`, or `null` when the source value is absent.

| Field | Type | Description |
|---|---|---|
| `internationalRegistrationNumber` | string | WIPO international registration number (unique per mark). |
| `markText` | string | The trademark text. |
| `status` | string | Status code: `ACT`, `INA` or `PEND`. |
| `statusLabel` | string | Human label: In force, No longer in force, Not yet in force. |
| `registrationDate` | string | International registration date (`YYYY-MM-DD`). |
| `expiryDate` | string | Date protection expires (`YYYY-MM-DD`). |
| `monthsToExpiry` | integer | Whole months from the run time to `expiryDate`. |
| `holderName` | string | Registered owner (holder) name. |
| `holderAddress` | string | Holder full postal address. |
| `holderCountry` | string | Two-letter ISO country code of the holder. |
| `representativeName` | string | IP law firm or attorney of record, or `null` if none. |
| `representativeAddress` | string | Representative postal address. |
| `representativeCountry` | string | Two-letter ISO country code of the representative. |
| `originOffice` | string | Office of origin the registration was filed from. |
| `designatedCountries` | string\[] | Territories where protection is sought. |
| `designatedCountriesCount` | integer | Count of designated territories. |
| `niceClasses` | integer\[] | Nice classification class numbers covered. |
| `niceClassCount` | integer | Count of Nice classes. |
| `basicApplicationNumber` | string | National basic application number, or `null` (enrichment). |
| `basicRegistrationNumber` | string | National basic registration number, or `null` (enrichment). |
| `hasContactEmailOnFile` | boolean | Whether the register holds a contact email for the mark. |
| `holderNationality` | string | Holder nationality, or `null` (enrichment). |
| `holderLegalNature` | string | Corporate form and jurisdiction, for example `Corporation, California, United States` (enrichment). |
| `goodsServices` | string | Goods and services wording per Nice class, in English (enrichment). |
| `goodsServicesClassCount` | integer | Number of classes with goods and services wording (enrichment). |
| `useRequirementCountries` | string\[] | Territories that carry a declaration-of-use requirement (enrichment). |
| `protectedCountries` | string\[] | Territories that granted protection (enrichment). |
| `protectedCountriesCount` | integer | Count of territories that granted protection (enrichment). |
| `refusedCountries` | string\[] | Territories that issued a refusal (enrichment). |
| `refusedCountriesCount` | integer | Count of refusing territories (enrichment). |
| `opposedCountries` | string\[] | Territories where the mark was opposed (enrichment). |
| `renewalCount` | integer | Number of renewals recorded (enrichment). |
| `transactionCount` | integer | Number of transactions in the registration ledger (enrichment). |
| `lastTransactionCode` | string | Code of the latest recorded transaction (enrichment). |
| `lastTransactionDate` | string | Date of the latest recorded transaction (enrichment). |
| `basicApplicationCountry` | string | Country of the basic application, or `null` (enrichment). |
| `basicApplicationDate` | string | Date of the basic application, or `null` (enrichment). |
| `basicRegistrationCountry` | string | Country of the basic registration (enrichment). |
| `basicRegistrationDate` | string | Date of the basic registration (enrichment). |
| `languageOfApplication` | string | Filing language (English, French or Spanish). |
| `gazetteNumber` | string | WIPO Gazette issue the registration was published in. |
| `matchedQuery` | string | Which search or filter matched this record. |
| `detailUrl` | string | Link to the registration on the WIPO Madrid Monitor. |
| `source` | string | Constant source label. |
| `observedAt` | string | ISO 8601 timestamp of when the record was collected. |
| `error` | string | Present only on a failed run, where a single item with a populated `error` field is written instead of results. |

Enrichment fields are populated when `fetchDetails` is on (the default). Fields marked `null` are genuinely absent for that mark in the source.

### Use cases

- **Renewal-deadline pipelines.** Set an expiry window plus a holder country to get every mark coming up for renewal, with the responsible IP firm already attached.
- **Trademark watch and clearance.** Monitor new registrations in your Nice classes and territories with a registration-date window.
- **Competitive and M\&A intelligence.** Pull an owner's entire international portfolio, including where protection failed.
- **IP firm business development.** Find owners filing into your jurisdiction, and see who currently represents them.
- **Refusal and opposition analysis.** Study which territories refuse or oppose marks in a given class.

### Run via API and CLI

Start a run via the REST API. Replace `YOUR_TOKEN` with your Apify API token.

```bash
curl -X POST "https://api.apify.com/v2/acts/scrapers_lat~wipo-madrid-trademarks-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"holderCountries":["DE"],"niceClasses":["9"],"expiringFrom":"2026-10-01","expiringTo":"2026-12-31","maxTrademarks":100}'
```

Apify CLI:

```bash
apify call scrapers_lat/wipo-madrid-trademarks-scraper \
  --input '{"brandNames":["apple"],"maxTrademarks":25}'
```

### Fetch results

Results land in the run's dataset and can be exported as JSON, CSV or Excel from the Apify console or the API:

```bash
curl "https://api.apify.com/v2/datasets/DATASET_ID/items?clean=true&format=csv&token=YOUR_TOKEN"
```

### Billing and limits

This actor uses pay-per-event pricing. You are only charged on a successful result.

| Event | Price (USD) | When it is charged |
|---|---|---|
| `result` | 0.015 | Once per international trademark registration written to the dataset. |

- **No charge on failure.** If a run errors, a single item with a populated `error` field is written and is not charged. Empty runs cost nothing.
- **Free Apify plans** are capped at 10 results per run; upgrade for larger pulls.
- **Spend cap respected.** Set `maxTotalChargeUsd` on the run to stop once a budget is reached.
- Set `maxTrademarks` to control run size and cost. The register holds about 1.4 million registrations, so use the filters to target the exact segment you need. Deep result sets page through in full.

### FAQ and troubleshooting

**Which trademarks are covered?** Every international registration in the Madrid System register: marks filed through WIPO that seek protection across the 130+ member territories. National-only marks that were never filed internationally are not part of this register.

**How fresh is the data?** It is read live from the public register on each run, and every record carries `observedAt` plus the registration's own `lastTransactionDate`.

**Why is `representativeName` sometimes `null`?** Not every holder appoints a representative; many file directly. The field is `null` when the register has no representative on record.

**What do `protectedCountries` and `refusedCountries` mean?** They are derived from the registration's own transaction history: territories that issued a statement of grant of protection, and territories that issued a refusal. A refusal later overturned by a grant is reported only as protected.

**Why is `goodsServices` shorter than the record page?** The register publishes the same wording in English, French and Spanish. This actor returns the English text (falling back to the filing language when no English version exists) so exports stay readable.

**Can I get more than the count I set?** No. `maxTrademarks` is a hard cap; the actor stops once it is reached.

**Do I need a proxy or an API key?** No. The source is a public register and needs neither.

***

Not affiliated with, endorsed by or sponsored by the World Intellectual Property Organization. All data is read from publicly available records.

# Actor input Schema

## `maxTrademarks` (type: `integer`):

Maximum number of international trademark registrations to collect. The register holds about 1.4 million registrations, so for large pulls narrow the search with the filters below.

## `brandNames` (type: `array`):

One or more trademark words to search for. Each entry runs as its own search and the results are merged and de-duplicated. Wildcards are supported, for example "nova\*".

## `holderNames` (type: `array`):

One or more trademark owner names to search for, for example "Nestle" or "Siemens". Each entry runs as its own search.

## `internationalRegNumbers` (type: `array`):

Look up specific international registrations by number, for example 1323866.

## `goodsServices` (type: `string`):

Free-text keyword matched against the goods and services wording, for example "software", "footwear" or "pharmaceutical". Combined with every other filter.

## `status` (type: `string`):

Restrict to registrations that are currently in force, no longer in force, not yet in force, or all of them.

## `niceClasses` (type: `array`):

Nice classification class numbers, for example 9, 35, 42. Leave empty for all classes.

## `holderCountries` (type: `array`):

Two-letter ISO country codes of the trademark owner's address, for example DE, US, CN. Leave empty for all countries.

## `originOffices` (type: `array`):

Two-letter codes of the office the international registration originated from, for example US, DE, EM (EU). Leave empty for all offices.

## `designatedCountries` (type: `array`):

Only return registrations that seek protection in these territories, for example BR, MX, JP. Leave empty for all designations.

## `expiringFrom` (type: `string`):

Only return registrations whose protection expires on or after this date. Combine with Expiring To to build a renewal-deadline pipeline.

## `expiringTo` (type: `string`):

Only return registrations whose protection expires on or before this date.

## `registeredFrom` (type: `string`):

Only return registrations dated on or after this date. Useful for monitoring newly registered marks.

## `registeredTo` (type: `string`):

Only return registrations dated on or before this date.

## `fetchDetails` (type: `boolean`):

When enabled (recommended), every registration is enriched from its full public record: goods and services wording per Nice class, holder legal nature and nationality, basic application and registration details, per-country protection granted, refusals, oppositions, renewals and the latest transaction. Disable for a faster, lighter run.

## Actor input object example

```json
{
  "maxTrademarks": 10,
  "brandNames": [
    "apple"
  ],
  "status": "ACT",
  "fetchDetails": 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 = {
    "maxTrademarks": 10,
    "brandNames": [
        "apple"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapers_lat/wipo-madrid-trademarks-scraper").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 = {
    "maxTrademarks": 10,
    "brandNames": ["apple"],
}

# Run the Actor and wait for it to finish
run = client.actor("scrapers_lat/wipo-madrid-trademarks-scraper").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 '{
  "maxTrademarks": 10,
  "brandNames": [
    "apple"
  ]
}' |
apify call scrapers_lat/wipo-madrid-trademarks-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,scrapers_lat/wipo-madrid-trademarks-scraper"
        }
    }
}

```

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/YZJDNp2SeRJWtCnoN/builds/9JytfOYsIwIlu0y7y/openapi.json
