# USPTO Trademark Scraper & API: Daily Status Changes (`friendlyapi/uspto-trademark-scraper`) Actor

The USPTO daily trademark firehose as clean, serial-keyed JSON events: watch serials for status changes, pull filtered event feeds (office actions, abandonments, registrations), audit dataset freshness for free. Built for legal-tech developers.

- **URL**: https://apify.com/friendlyapi/uspto-trademark-scraper.md
- **Developed by:** [FriendlyAPI](https://apify.com/friendlyapi) (community)
- **Categories:** Business, Developer tools, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 serial checkeds

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

## USPTO Trademark Scraper & API: daily status changes as clean JSON

The USPTO publishes every trademark prosecution event as a firehose of daily
XML, July 2026 alone was 31 files, 0.96 GB compressed, 1,108,850 case-file
transactions. This actor is that firehose as **clean, serial-keyed JSON
events**, for legal-tech builders who need trademark status changes in their
product, not another dashboard to log into.

Watch tools are normally sold per seat: Alt Legal runs **$55-95/user/month**,
and enterprise watch (Corsearch, TrademarkNow) starts around **$12,000/year**.
Those are fine products for attorneys clicking a UI. If you are *building* the
UI, docketing software, brand-monitoring dashboards, client alert emails, an
MCP tool for an agent, you want the events themselves, priced per event, with
provenance you can audit. That is this.

### What you get per event

```json
{
  "serial": "97123456",
  "mark": "EXAMPLE MARK",
  "owner_name": "EXAMPLE HOLDINGS LLC",
  "event_code": "GNRN",
  "event_label": "NOTIFICATION OF NON-FINAL ACTION E-MAILED",
  "event_date": "2026-07-14",
  "status_code": "641",
  "source_file": "apc260715.zip",
  "file_date": "2026-07-15",
  "row_hash": "1f0c2a..."
}
```

Every event carries USPTO's own code, label and date, the case's mark, owner
and status at that moment, and the exact daily file it came from, line-level
provenance back to the government record.

### Modes

| Mode | What it does | Billing |
|---|---|---|
| `watch_serials` | Events for your watch list of serial numbers (optional `since` date) | 1 `serial_check` event per serial |
| `events_feed` | Every event matching `since`/`until`/`codes`, for examplee.g. all abandonments this week, all non-final actions | 1 `events_100` event per 100 events returned |
| `dataset_info` | Freshness ledger: every daily file ingested, sha256, counts, build time | **Free** |

Typical builds on top: docket alerts ("your client's application got an
office action"), competitor watch by owner, abandonment lead-gen, deadline
trackers keyed on action mail dates, agent tools via MCP.

### The data honesty section

**Daily files lag their own events**, and the size of the lag moves month to
month, which is exactly why you cannot read "July's events" off July's files.
Two measurements, both ours:

| | Oct 2025 | Jul 2026 (this build) |
|---|---:|---:|
| Events dated the same day as their file | 55% | 89.2% |
| Events dated the day before | 45% | 10.2% |
| Within 3 days | n/a | 99.9% |
| Tail | ~2 weeks back | ~2 weeks back |

We handle that the only correct way: events are keyed on their **own** dates,
every daily file is re-scanned across a 21-day trailing window, and duplicates
are dropped on a content hash. That re-scan is not theatre: building July 2026
offered **2,969,278** event rows and stored **1,939,629** unique ones, so
**34.7%** of what the files carried was a re-delivery the hash caught.

Consequences for you, stated plainly:

- An event dated `D` can first become *visible* up to ~2 weeks after `D`
  (in July 2026, 99.9% arrived within 3 days).
- If you poll `events_feed` by date, **overlap your windows**, or move onto
  the `after_id` cursor, which walks events in ingestion order and never
  misses a late arrival. To hand off from a date query to the cursor, keep
  paging until a run comes back with `cursor_safe: true` (meaning the range
  was drained, not truncated by `limit`), then carry that run's
  `next_after_id` forward. Switching from a truncated page would skip rows,
  so we tell you when it is safe instead of leaving you to find out.

`dataset_info` shows exactly which daily files are in the build, each file's
sha256, and per-file event counts. Audit us before you trust us, it's free.

### What this is NOT

- **Not legal advice, and not a law firm.** It is a data feed derived from
  public USPTO bulk files. Deadlines, responses and filings belong with a
  licensed attorney.
- **Not a docketing system.** No deadline math, no reminders, no workflow,
  it is the clean event stream you build those on.
- **Not a status-lookup tool, and not the whole register.** This is the one
  difference worth reading twice, because most USPTO actors on this Store are
  lookup tools and this is not one. They answer "what is the status of mark X
  right now" for any mark ever filed. This answers "what changed, across the
  register, since date D". You cannot build a portfolio watch on a lookup tool
  without polling it once per mark, and you cannot ask it for every abandonment
  this week at all. The trade is that we carry a **rolling window of the last
  45 business days**, published in `coverage` on every response, so a dormant
  mark returns no events and says so explicitly. For the lifetime status of a
  single mark, use TSDR or one of those lookup actors; they are better at it.
- **Not real-time TSDR.** Source cadence is USPTO's daily bulk publication
  plus the lag described above. For a live single-case check, TSDR's website
  is the authority.
- **Not the Madrid/international history stream.** v1 emits the case-file
  prosecution events (the classic TSDR history); Madrid-specific history
  events are on the roadmap.

### Event codes you'll actually filter on

Every code below was **counted in our own July 2026 build**, not copied from a
reference table, the number after each one is how many times it occurred in
that month, so you can size a filter before you spend anything. 442 distinct
codes appear in total.

| Code | Meaning | Jul 2026 |
|---|---|---:|
| `CNRT` | Non-final action, written | 45,761 |
| `GNRT` | Non-final action, e-mailed | 42,742 |
| `GNRN` | Notification of non-final action e-mailed | 42,749 |
| `CNFR` / `GNFR` | Final refusal (written / e-mailed) | 6,236 / 6,230 |
| `CPRA` / `GPRA` / `GPRN` | Priority action (written / e-mailed / notified) | 143 / 136 / 138 |
| `ABN2` | Abandonment, failure to respond or late response | 17,286 |
| `ABN6` | Abandonment, no use statement filed | 12,294 |
| `NOAM` | Notice of allowance e-mailed, SOU required | 24,092 |
| `PUBO` | Published for opposition | 53,789 |
| `R.PR` | **Registered, Principal Register** | 51,420 |
| `R.SR` | Registered, Supplemental Register | 1,188 |
| `RNL1` / `RNL2` / `RNL3` | Registered and renewed (1st / 2nd / 3rd, 10 yrs) | 10,204 / 3,677 / 1,739 |
| `8.OK` / `89AG` | Sec. 8 (6-yr) accepted / Sec. 8 (10-yr) + Sec. 9 granted | 8,566 / 15,706 |

Two traps worth naming, because guessing the code is the easy mistake:
registration is **`R.PR`**, not `REGR`, the code has a dot in it, and each
abandonment has a *paired* notice code (`ABN2` pairs with `MAB2`, `ABN6` with
`MAB6`), so filtering on both double-counts the same abandonment.

Case status codes (e.g. `641` NON-FINAL ACTION - MAILED, `800` REGISTERED AND
RENEWED) are labeled from USPTO's own status-code table, Live/Dead flag
included. Any code not in this table still ships, with USPTO's own
`event_label` from the file, never a blank.

### Scheduling a watch

Create a Task with your `serials` list and a `since` date, add a daily
schedule, and point your webhook/integration at the dataset. Each run bills
only the serials checked. For a firehose consumer, schedule `events_feed`
with your code filter and carry `next_after_id` forward between runs.

**Support:** friendlyapidev@gmail.com

***

## Terms of Use

**Effective 9 August 2026.** These Terms govern this and every other data service published by the Provider. "The Provider" means the operator of the Service, reachable at **friendlyapidev@gmail.com**. "The user" means anyone who accesses the Service, paid or free. By using it you agree to them.

*§1's consumer-reporting provisions and §5's prohibition on decisions about individuals are directed principally at services that return records about named people.*

### 1. What this service is

The Service provides **structured data compiled from public government
sources**. It is an information product. It is **not** legal advice, not a
compliance determination, and not a background-check or consumer report.

Nothing in the Service constitutes a verdict about any person or entity. The
Service returns **candidate matches with confidence scores and source
provenance**, which a competent human must review before any action is taken.

**The Provider is not a consumer reporting agency**, and nothing the Service
returns is a "consumer report" or "investigative consumer report" within the
meaning of the Fair Credit Reporting Act (15 U.S.C. § 1681 et seq.) or any
state analogue. The Service is not assembled or evaluated for the purpose of
establishing a consumer's eligibility for employment, credit, insurance, or
housing, and the Provider does not follow the procedures the FCRA requires of
consumer reporting agencies. Permitted uses are set out in §5.

### 2. No warranty

THE SERVICE AND ALL DATA ARE PROVIDED "AS IS" AND "AS AVAILABLE", WITHOUT
WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY
WARRANTY OF ACCURACY, COMPLETENESS, CURRENCY, MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE, OR NON-INFRINGEMENT.

Specifically, and without limiting the above, the Provider does **not**
warrant that:

- the data is complete, current, or free from error;
- every relevant record has been collected, or that any particular
  jurisdiction, list, or record is included;
- a "no match" result means a person or entity is not subject to any
  exclusion, sanction, action, or legal obligation;
- source publications will remain available, unchanged in format, or on any
  particular schedule.

### 3. The data comes from third parties we do not control

All data is derived from **public government publications**. Those publishers
control what they publish, when, in what format, and whether it is accurate.
They change formats without notice, take sites offline, and publish records
containing their own errors. The Provider reproduces and normalises what those
sources publish and **does not independently verify the truth of any
underlying record**.

Each result identifies the source it came from, and the Service publishes the
as-of date and official URL of every source it carries, so any result can be
checked against the government publication it derives from.

### 4. The user's verification duty

The user is solely responsible for verifying any result against the official
primary source before relying on it or acting on it, and for obtaining
professional advice appropriate to their circumstances.

**The Service's published coverage statement is part of these Terms.** It
states which jurisdictions are collected automatically, which are published by
their source in a form the Service does not collect, and which publish nothing
at all. A user who acts on the Service without reading it does so at their own
risk.

### 5. Acceptable use

**Permitted.** Query the Service, integrate it into your own product, and
display individual results to your own users, including as part of a
compliance workflow you operate.

**Prohibited.** The user shall not:

1. **Use the Service, in whole or in part, as a factor in any decision about
   an individual's employment, engagement, retention, promotion, credit,
   insurance, housing, or eligibility for any benefit.** The Service is not a
   consumer report (§1). Screening obligations that arise from law or
   regulation must be discharged against the official primary source, and any
   decision about a person must rest on that verified source and the user's
   own judgement, not on this Service.
2. Extract, copy, or redistribute the dataset in bulk, or use it to build,
   train, or populate a competing dataset or data feed. (Querying the Service
   and showing results to your own users is expressly permitted above.)
3. Use the Service in violation of any law, or to re-identify, harass, or
   defame any individual appearing in the data.

A record in these datasets means only that a government body published it.
It is not a finding by the Provider about any person.

### 6. Limitation of liability

TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE PROVIDER SHALL NOT BE LIABLE FOR
ANY INDIRECT, INCIDENTAL, SPECIAL, CONSEQUENTIAL, EXEMPLARY, OR PUNITIVE
DAMAGES, OR FOR ANY LOSS OF PROFITS, REVENUE, DATA, GOODWILL, OR BUSINESS
OPPORTUNITY, ARISING OUT OF OR RELATING TO THE SERVICE, WHETHER IN CONTRACT,
TORT (INCLUDING NEGLIGENCE), OR ANY OTHER THEORY, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

THE PROVIDER'S TOTAL AGGREGATE LIABILITY ARISING OUT OF OR RELATING TO THE
SERVICE, IN THE AGGREGATE AND FOR ALL CLAIMS COMBINED, SHALL NOT EXCEED **ONE
HUNDRED US DOLLARS (US$100)**.

The user acknowledges that this limitation is a material part of the bargain,
that the fees charged reflect it, and that the Provider would not offer the
Service on these terms without it.

Two notes on why the cap is a flat figure rather than a multiple of fees. It
is never zero. A cap of zero for a user who paid nothing invites the argument
that the clause is illusory, and a court that agrees may strike the whole
limitation rather than read it down. And it is fixed rather than computed, so
there is nothing to reconstruct from billing records years later.

Nothing in these Terms excludes or limits liability that cannot lawfully be
excluded or limited. If any part of this section is held unenforceable, the
remainder continues to apply to the fullest extent permitted.

### 7. Indemnity

The user shall indemnify and hold the Provider harmless from any claim arising
from the user's use of the Service, including any decision made in reliance on
it and any breach of §5.

### 8. Availability and changes

The Service may change, add, or remove data sources and coverage at any time,
and may be unavailable. Changes to coverage are reflected in the published
coverage statement.

### 9. Governing law

These Terms are governed by the laws of the **State of New York**, without
regard to conflict-of-laws principles. The parties submit to the **exclusive
jurisdiction of the state and federal courts located in the State of New
York**, and each waives any objection to that venue.

Disputes are resolved in court; these Terms do not require arbitration.

### Pricing

Pay per event, no subscription. Prices fall on higher Apify plans.

| Event | What triggers it | Price |
|---|---|---|
| `serial_check` | One serial number checked for events | **$0.005** (from $0.003) |
| `events_100` | Per 100 events returned by a feed query | **$0.02** (from $0.012) |

`dataset_info`, the freshness and coverage ledger, is **free**. Watching a
200 mark portfolio daily is $1 a day. Per-seat watch tools start at $55 a
month per user.

### 10. Contact

**friendlyapidev@gmail.com**

Support is handled by email. There is no telephone support and no guaranteed
response time.

***

# Actor input Schema

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

watch\_serials = events for your watch list; events\_feed = all events matching a date/code filter; dataset\_info = dataset freshness (free)

## `serials` (type: `array`):

USPTO application serial numbers to check, e.g. \["97123456", "79345678"]

## `since` (type: `string`):

ISO date (e.g. 2026-07-01). watch\_serials: only events on/after this date. events\_feed: required unless after\_id is used.

## `until` (type: `string`):

Optional ISO upper bound on event dates.

## `codes` (type: `array`):

Optional USPTO event codes, e.g. \["CNRT", "GNRN", "ABN2"]. Empty = all codes.

## `after_id` (type: `integer`):

Ingestion-order cursor from the previous run's next\_after\_id. Never misses late-arriving events; overrides since/until.

## `limit` (type: `integer`):

1-5000, default 1000.

## `offset` (type: `integer`):

Pagination offset when using since/until. Prefer after\_id for polling.

## Actor input object example

```json
{
  "mode": "watch_serials",
  "serials": [
    "98412146",
    "88851003"
  ]
}
```

# Actor output Schema

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

Serial-keyed USPTO events, newest first.

## `csv` (type: `string`):

For docketing and spreadsheet workflows.

## `runInConsole` (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 = {
    "mode": "watch_serials",
    "serials": [
        "98412146",
        "88851003"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("friendlyapi/uspto-trademark-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 = {
    "mode": "watch_serials",
    "serials": [
        "98412146",
        "88851003",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("friendlyapi/uspto-trademark-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 '{
  "mode": "watch_serials",
  "serials": [
    "98412146",
    "88851003"
  ]
}' |
apify call friendlyapi/uspto-trademark-scraper --silent --output-dataset

```

## MCP server setup

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