# USPTO Trademark Watch — New Filings & Status, No Login, $20/1k (`outstanding_vegetable/uspto-trademark-watch`) Actor

Watch USPTO trademarks by word mark, owner, Nice class or serial number and get only NEW applications and status changes since the last run, with owner, attorney, classes, goods and TSDR link. Weekly schedule. No login or API key. MCP-ready. $20 per 1,000 alerts.

- **URL**: https://apify.com/outstanding\_vegetable/uspto-trademark-watch.md
- **Developed by:** [Peter Skotte](https://apify.com/outstanding_vegetable) (community)
- **Categories:** Lead generation, Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $20.00 / 1,000 alerts

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

## USPTO Trademark Watch — new filings & status alerts, no API key

A trademark watch service you schedule yourself. Each run reports **only the new USPTO applications that
match your word marks, owner names and Nice classes**, plus **status and office-action changes on the serial
numbers you are tracking**. The monitor remembers everything it has already reported, so a weekly run
emits just the delta, posts a summary to your webhook, and costs you only for what actually changed.
No USPTO login, no API key, no TESS/TSDR clicking.

Built for IP paralegals, brand owners and law firms who pay $50+/month for watch subscriptions and want
the same feed inside their own docketing, Slack or spreadsheet.

### How it works

1. Queries the public USPTO trademark search backend (the same index that powers tmsearch.uspto.gov, updated
   the morning after each filing day) for applications **filed in the last `filedSinceDays`** whose word mark
   contains a word starting with one of your `watchTerms`, or whose applicant matches one of your
   `ownerNames`, optionally limited to `niceClasses`.
2. For every unseen filing it pulls the TSDR case record (status, status date, owner address, attorney,
   latest prosecution-history event) and emits it with `changeType: "new"`.
3. For every serial in `watchSerials` it compares the current status, status date and latest prosecution
   event against the saved state and emits a record when anything changed (`changeType: "updated"`), or once
   with the current status the first time the serial is added (`changeType: "new"`).
4. Saves the state, then POSTs a run summary to `webhookUrl` if set.

State lives in a named key-value store `tm-watch-<hash of monitorId>` in your Apify account, capped at 50,000
serial numbers (oldest dropped first). Delete the store to reset a monitor.

### Input

| Field | Default | Notes |
|---|---|---|
| `watchTerms` | `["apple", "nimbus"]` | Word-mark watches. `apple` matches APPLE, APPLEGATE FARM, GOLDEN APPLE (word-prefix match on the mark and its pseudo mark). One watch per term |
| `ownerNames` | `[]` | Applicant watches, phrase match on the owner name: `["Nike"]`, `["Procter & Gamble"]` |
| `niceClasses` | `[]` | Restrict word-mark and owner watches to classes, e.g. `["9", "42"]`. Empty = all |
| `watchSerials` | `[]` | 8-digit application serial numbers to track for status changes |
| `filedSinceDays` | `7` | Only applications filed within N days. 7 for a weekly schedule, 30 for a first baseline |
| `maxNewPerTerm` | `5` | Cap on new filings per watch term per run; the rest come out next run |
| `maxItems` | `10` | Overall cap on records per run |
| `firstRunMode` | `emitAll` | `emitAll` reports every current match on the first run; `baseline` records them silently |
| `webhookUrl` | `""` | Optional POST target for the run summary |
| `monitorId` | `default` | One state store per ID: run one monitor per client or brand |
| `usptoApiKey` | `""` | Optional key from account.uspto.gov/api-manager for the official TSDR API. Not required |

### Recommended setup for a weekly watch

1. Create a task per client or brand family and set `monitorId` accordingly (`acme-brands`).
2. Put the client's marks in `watchTerms` (short distinctive elements work best: `zephyr`, `nimbus`,
   `bluefin`) and their competitors in `ownerNames`. Add `niceClasses` if the client only cares about,
   say, classes 9, 35 and 42.
3. **First run: set `firstRunMode` to `baseline` and `filedSinceDays` to 30.** This records everything
   currently matching without emitting a backlog.
4. Switch `firstRunMode` back to `emitAll` (it only matters while the state is empty), set
   `filedSinceDays` to 10 for a weekly schedule (a safe overlap; the state prevents duplicates) and raise
   `maxNewPerTerm` / `maxItems` to whatever you are willing to review.
5. Add the serials of the client's own pending applications and any opposed marks to `watchSerials` to be
   told when they are assigned to an examiner, get an office action, are published for opposition,
   register, or go abandoned.
6. **Schedule weekly**, e.g. Monday 07:00 America/New\_York. New filings appear in the USPTO index the
   morning after they are filed.
7. Point `webhookUrl` at Slack, Zapier, Make or your docketing system.

The default settings (`{}`) run in `emitAll` mode for the terms `apple` and `nimbus` so you see real output
on the first try.

### Example: brand watch for a client in software and apparel

```json
{
  "watchTerms": ["zephyr", "zephyrly"],
  "ownerNames": ["Zephyr Labs"],
  "niceClasses": ["9", "25", "42"],
  "watchSerials": ["98123456", "98234567"],
  "filedSinceDays": 10,
  "maxNewPerTerm": 50,
  "maxItems": 500,
  "firstRunMode": "baseline",
  "webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
  "monitorId": "zephyr-labs"
}
```

Other quick profiles:

- **Competitor filings**: `watchTerms: []`, `ownerNames: ["Nike", "Adidas", "Puma"]`, `niceClasses: ["25", "28"]`
- **Docket status only**: `watchTerms: []`, `watchSerials: [...]` and a daily schedule
- **Class sweep**: `watchTerms: ["ai", "gpt"]`, `niceClasses: ["9", "42"]`

### Output

One record per new filing or status change:

```json
{
  "serialNumber": "50122612",
  "registrationNumber": null,
  "markText": "NIMBUS VERSE",
  "markType": "TRADEMARK",
  "drawingType": "(4) STANDARD CHARACTER MARK",
  "owner": "Bozhou (Hong Kong) Co., Limited",
  "ownerAddress": "FLAT A 10/F, BLOCK A, TUNG CHUN INDUSTRIAL BUILDING, 9-11 CHEUNG WING ROAD, KWAI CHUNG, NEW TERRITORIES, Hong Kong, 999077, China",
  "filingDate": "2026-09-22",
  "registrationDate": null,
  "status": "NEW APPLICATION - RECORD INITIALIZED NOT ASSIGNED TO EXAMINER",
  "statusDetail": "LIVE/APPLICATION/Awaiting Examination",
  "statusDate": "2026-09-22",
  "liveDead": "Live",
  "publicationDate": null,
  "niceClasses": ["028"],
  "goodsServices": "IC 028: Party balloons; Golf balls; Golf tees; Golf accessories, namely, ...",
  "attorney": "William Bak",
  "lastEventDate": "2026-09-22",
  "lastEvent": "APPLICATION FILING RECEIPT MAILED",
  "tsdrUrl": "https://tsdr.uspto.gov/#caseNumber=50122612&caseType=SERIAL_NO&searchType=statusSearch",
  "matchedTerm": "nimbus",
  "changeType": "new",
  "firstSeenAt": "2026-09-28T19:14:30.872Z",
  "monitorId": "default"
}
```

`matchedTerm` is the watch term or owner name that matched, or `serial:<number>` for serial watches.
`goodsServices` is truncated to 500 characters; the full identification is one click away on `tsdrUrl`.
`niceClasses` uses the USPTO three-digit form (`"009"`).

### Webhook payload

POSTed once per run as `application/json`, also saved as the `SUMMARY` record in the run's key-value store:

```json
{
  "monitorId": "zephyr-labs",
  "runAt": "2026-09-29T11:00:03.118Z",
  "newCount": 3,
  "updatedCount": 1,
  "scanned": 41,
  "seenTotal": 212,
  "baseline": false,
  "records": [ { "...first 50 records, same shape as the dataset..." } ]
}
```

### Pricing

Pay per event: a small start fee plus a per-alert fee **only for records emitted**. A weekly watch that
finds nothing new costs just the start fee.

### Notes

- Word-mark matching is word-prefix based: `apple` matches `APPLEGATE` but not `PINEAPPLE`. Use several
  short terms to cover variants.
- Word-mark and owner watches only report **new** filings; to follow a filing after you have seen it, add
  its serial to `watchSerials`.
- A watch scans at most 1,000 filings per run (newest first). Narrow with `niceClasses` or a shorter
  `filedSinceDays` if a term is that common.
- The status snapshot comes from TSDR and takes a few seconds per record; large watchlists take
  correspondingly longer but cost the same.

# Actor input Schema

## `watchTerms` (type: `array`):

New applications whose word mark (or pseudo mark) contains a word starting with this text are reported. "apple" matches APPLE, APPLEGATE FARM and GOLDEN APPLE. One watch per term; each term gets its own maxNewPerTerm budget.

## `ownerNames` (type: `array`):

New applications filed by these owners (phrase match on the applicant name, e.g. "Nike", "Procter & Gamble"). Works alongside watchTerms; each name is its own watch.

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

Restrict the word-mark and owner watches to these international classes, e.g. \["9", "42"]. Empty = all 45 classes. Does not apply to watchSerials.

## `watchSerials` (type: `array`):

USPTO application serial numbers (8 digits) whose status you want to track. The first run reports each one's current status (changeType new); later runs report only when the status, status date or latest prosecution-history event changes (changeType updated).

## `filedSinceDays` (type: `integer`):

Only consider applications filed within this many days. 7 suits a weekly schedule; use 30 for a first baseline.

## `maxNewPerTerm` (type: `integer`):

Stop scanning a word-mark or owner watch after this many new filings. Filings beyond the cap stay unseen and come out on the next run.

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

Overall cap on emitted records (new filings plus serial status changes) per run.

## `firstRunMode` (type: `string`):

What to do when the monitor has no saved state yet. emitAll: report every current match (good for a first test). baseline: silently record every current match and emit nothing, so the next scheduled run reports only what is new since.

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

Optional. After each run a JSON summary {monitorId, runAt, newCount, updatedCount, records\[first 50]} is POSTed here (Slack, Zapier, Make, your docketing system).

## `monitorId` (type: `string`):

Name of this watchlist. Each ID keeps its own seen-state in a key-value store named tm-watch-<hash>, so you can run one monitor per client or brand side by side.

## `usptoApiKey` (type: `string`):

Optional key from https://account.uspto.gov/api-manager/ for the official TSDR API. Without it the actor uses the keyless TSDR backend of tmsearch.uspto.gov, which works fine; a key only matters if you run very large watchlists and want to stay within your own quota.

## Actor input object example

```json
{
  "watchTerms": [
    "apple",
    "nimbus"
  ],
  "ownerNames": [],
  "niceClasses": [],
  "watchSerials": [],
  "filedSinceDays": 7,
  "maxNewPerTerm": 5,
  "maxItems": 10,
  "firstRunMode": "emitAll",
  "webhookUrl": "",
  "monitorId": "default"
}
```

# Actor output Schema

## `records` (type: `string`):

Dataset of new trademark filings and status changes found in this run (JSON).

# 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 = {
    "watchTerms": [
        "apple",
        "nimbus"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("outstanding_vegetable/uspto-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 = { "watchTerms": [
        "apple",
        "nimbus",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("outstanding_vegetable/uspto-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 '{
  "watchTerms": [
    "apple",
    "nimbus"
  ]
}' |
apify call outstanding_vegetable/uspto-trademark-watch --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,outstanding_vegetable/uspto-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/0HBVS7HhSH7td6axI/builds/sOBzy5S2lpBYzdpPg/openapi.json
