@biggora/claude-plugins 1.1.1 → 1.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/settings.local.json +3 -1
- package/README.md +24 -17
- package/package.json +1 -1
- package/registry/registry.json +319 -244
- package/specs/coding.md +24 -0
- package/specs/pod.md +2 -0
- package/src/skills/captcha/README.md +221 -0
- package/src/skills/captcha/SKILL.md +355 -0
- package/src/skills/captcha/references/captcha-types.md +254 -0
- package/src/skills/captcha/references/services.md +172 -0
- package/src/skills/captcha/references/stealth.md +238 -0
- package/src/skills/captcha/scripts/solve_captcha.py +323 -0
- package/src/skills/captcha/scripts/solve_image_grid.py +350 -0
- package/src/skills/codex-cli/SKILL.md +21 -11
- package/src/skills/gemini-cli/SKILL.md +27 -13
- package/src/skills/gemini-cli/references/commands.md +21 -14
- package/src/skills/gemini-cli/references/configuration.md +23 -18
- package/src/skills/gemini-cli/references/headless-and-scripting.md +7 -17
- package/src/skills/gemini-cli/references/mcp-and-extensions.md +12 -6
- package/src/skills/google-merchant-api/SKILL.md +581 -0
- package/src/skills/google-merchant-api/references/accounts.md +247 -0
- package/src/skills/google-merchant-api/references/content-api-legacy.md +216 -0
- package/src/skills/google-merchant-api/references/datasources.md +233 -0
- package/src/skills/google-merchant-api/references/inventories.md +201 -0
- package/src/skills/google-merchant-api/references/migration.md +267 -0
- package/src/skills/google-merchant-api/references/products.md +316 -0
- package/src/skills/google-merchant-api/references/promotions.md +201 -0
- package/src/skills/google-merchant-api/references/reports.md +240 -0
- package/src/skills/lv-aggregators-api/SKILL.md +113 -0
- package/src/skills/lv-aggregators-api/references/integration-guide.md +368 -0
- package/src/skills/lv-aggregators-api/references/kurpirkt.md +103 -0
- package/src/skills/lv-aggregators-api/references/salidzini.md +122 -0
- package/src/skills/notebook-lm/SKILL.md +1 -1
- package/src/skills/screen-recording/SKILL.md +243 -213
- package/src/skills/screen-recording/references/design-patterns.md +4 -2
- package/src/skills/screen-recording/references/ffmpeg-recording.md +473 -0
- package/src/skills/screen-recording/references/{approach1-programmatic.md → programmatic-generation.md} +45 -22
- package/src/skills/screen-recording/references/python-fallback.md +222 -0
- package/src/skills/tailwindcss-best-practices/SKILL.md +180 -0
- package/src/skills/tailwindcss-best-practices/references/best-practices-utility-patterns.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/core-installation.md +109 -0
- package/src/skills/tailwindcss-best-practices/references/core-preflight.md +200 -0
- package/src/skills/tailwindcss-best-practices/references/core-responsive.md +163 -0
- package/src/skills/tailwindcss-best-practices/references/core-source-detection.md +114 -0
- package/src/skills/tailwindcss-best-practices/references/core-theme.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/core-utility-classes.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/core-variants.md +204 -0
- package/src/skills/tailwindcss-best-practices/references/effects-form-controls.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/effects-mask.md +91 -0
- package/src/skills/tailwindcss-best-practices/references/effects-scroll-snap.md +59 -0
- package/src/skills/tailwindcss-best-practices/references/effects-text-shadow.md +78 -0
- package/src/skills/tailwindcss-best-practices/references/effects-transition-animation.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/effects-visibility-interactivity.md +82 -0
- package/src/skills/tailwindcss-best-practices/references/features-content-detection.md +175 -0
- package/src/skills/tailwindcss-best-practices/references/features-custom-styles.md +203 -0
- package/src/skills/tailwindcss-best-practices/references/features-dark-mode.md +137 -0
- package/src/skills/tailwindcss-best-practices/references/features-functions-directives.md +241 -0
- package/src/skills/tailwindcss-best-practices/references/features-upgrade.md +160 -0
- package/src/skills/tailwindcss-best-practices/references/layout-aspect-ratio.md +39 -0
- package/src/skills/tailwindcss-best-practices/references/layout-columns.md +80 -0
- package/src/skills/tailwindcss-best-practices/references/layout-display.md +110 -0
- package/src/skills/tailwindcss-best-practices/references/layout-flexbox.md +112 -0
- package/src/skills/tailwindcss-best-practices/references/layout-grid.md +87 -0
- package/src/skills/tailwindcss-best-practices/references/layout-height.md +97 -0
- package/src/skills/tailwindcss-best-practices/references/layout-inset.md +103 -0
- package/src/skills/tailwindcss-best-practices/references/layout-logical-properties.md +92 -0
- package/src/skills/tailwindcss-best-practices/references/layout-margin.md +126 -0
- package/src/skills/tailwindcss-best-practices/references/layout-min-max-sizing.md +63 -0
- package/src/skills/tailwindcss-best-practices/references/layout-object-fit-position.md +64 -0
- package/src/skills/tailwindcss-best-practices/references/layout-overflow.md +57 -0
- package/src/skills/tailwindcss-best-practices/references/layout-padding.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/layout-position.md +85 -0
- package/src/skills/tailwindcss-best-practices/references/layout-tables.md +67 -0
- package/src/skills/tailwindcss-best-practices/references/layout-width.md +102 -0
- package/src/skills/tailwindcss-best-practices/references/transform-base.md +68 -0
- package/src/skills/tailwindcss-best-practices/references/transform-rotate.md +70 -0
- package/src/skills/tailwindcss-best-practices/references/transform-scale.md +83 -0
- package/src/skills/tailwindcss-best-practices/references/transform-skew.md +62 -0
- package/src/skills/tailwindcss-best-practices/references/transform-translate.md +77 -0
- package/src/skills/tailwindcss-best-practices/references/typography-font-text.md +142 -0
- package/src/skills/tailwindcss-best-practices/references/typography-list-style.md +65 -0
- package/src/skills/tailwindcss-best-practices/references/typography-text-align.md +60 -0
- package/src/skills/tailwindcss-best-practices/references/visual-background.md +76 -0
- package/src/skills/tailwindcss-best-practices/references/visual-border.md +108 -0
- package/src/skills/tailwindcss-best-practices/references/visual-effects.md +111 -0
- package/src/skills/tailwindcss-best-practices/references/visual-svg.md +82 -0
- package/src/skills/test-mobile-app/SKILL.md +11 -6
- package/src/skills/test-mobile-app/scripts/analyze_apk.py +15 -4
- package/src/skills/test-mobile-app/scripts/check_environment.py +5 -5
- package/src/skills/test-mobile-app/scripts/run_tests.py +1 -1
- package/src/skills/test-web-ui/SKILL.md +264 -84
- package/src/skills/test-web-ui/scripts/discover.py +25 -12
- package/src/skills/test-web-ui/scripts/run_tests.py +3 -2
- package/src/skills/tm-search/SKILL.md +242 -106
- package/src/skills/tm-search/references/scraping-fallback.md +60 -95
- package/src/skills/tm-search/scripts/tm_search.py +453 -375
- package/src/skills/vite-best-practices/SKILL.md +115 -0
- package/src/skills/vite-best-practices/references/build-and-ssr.md +255 -0
- package/src/skills/vite-best-practices/references/core-config.md +231 -0
- package/src/skills/vite-best-practices/references/core-features.md +222 -0
- package/src/skills/vite-best-practices/references/core-plugin-api.md +294 -0
- package/src/skills/vite-best-practices/references/environment-api.md +108 -0
- package/src/skills/vite-best-practices/references/rolldown-migration.md +242 -0
- package/src/skills/screen-recording/references/approach2-xvfb.md +0 -232
|
@@ -16,123 +16,283 @@ description: >
|
|
|
16
16
|
|
|
17
17
|
This skill enables an agent to search, validate, and analyze US trademarks via USPTO APIs.
|
|
18
18
|
|
|
19
|
-
## API
|
|
19
|
+
## Important: API Access Reality
|
|
20
|
+
|
|
21
|
+
The USPTO trademark search system (`tmsearch.uspto.gov`) uses **AWS WAF bot protection** on its
|
|
22
|
+
Elasticsearch search backend. Direct keyword search via HTTP is **not possible** without browser
|
|
23
|
+
automation. However, the **TSDR details API** (case lookup by serial number) works without
|
|
24
|
+
authentication and returns JSON.
|
|
25
|
+
|
|
26
|
+
For **keyword search**, use one of these approaches:
|
|
27
|
+
1. **Playwright/browser automation** — drive the tmsearch.uspto.gov web UI (most reliable)
|
|
28
|
+
2. **Third-party API** — RapidAPI USPTO wrapper (requires API key, simpler to use)
|
|
20
29
|
|
|
21
|
-
|
|
30
|
+
For **case status lookup by serial number**, the built-in TSDR API works directly.
|
|
22
31
|
|
|
23
|
-
|
|
32
|
+
## API Overview
|
|
33
|
+
|
|
34
|
+
| Use Case | Approach |
|
|
24
35
|
|---|---|
|
|
25
|
-
| Keyword/name text search
|
|
26
|
-
|
|
|
27
|
-
| Batch
|
|
36
|
+
| Keyword/name text search | Browser automation on tmsearch.uspto.gov **or** RapidAPI |
|
|
37
|
+
| Case status by serial number | TSDR Details API (no auth, JSON) |
|
|
38
|
+
| Batch keyword validation | Browser automation + delays **or** RapidAPI |
|
|
39
|
+
| Case documents / images | TSDR API (requires API key since Oct 2024) |
|
|
28
40
|
|
|
29
41
|
---
|
|
30
42
|
|
|
31
|
-
## API 1:
|
|
43
|
+
## API 1: TSDR Details API (No auth required — JSON)
|
|
32
44
|
|
|
33
|
-
|
|
34
|
-
|
|
45
|
+
Look up trademark case details **by serial number**. This endpoint is hosted on the tmsearch
|
|
46
|
+
site and returns JSON without authentication.
|
|
35
47
|
|
|
36
|
-
###
|
|
48
|
+
### Endpoint
|
|
37
49
|
|
|
38
50
|
```
|
|
39
|
-
|
|
40
|
-
Content-Type: application/json
|
|
51
|
+
GET https://tmsearch.uspto.gov/tsdr-api-v1-0-0/tsdr-api?serialNumber={SERIAL_NUMBER}
|
|
41
52
|
```
|
|
42
53
|
|
|
43
|
-
|
|
44
|
-
```json
|
|
45
|
-
{
|
|
46
|
-
"keyword": "APPLE",
|
|
47
|
-
"searchType": "1",
|
|
48
|
-
"statusType": "A",
|
|
49
|
-
"pluralVariants": false,
|
|
50
|
-
"start": 0,
|
|
51
|
-
"rows": 25
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
**Parameters:**
|
|
56
|
-
- `keyword` — the word/phrase to search (required)
|
|
57
|
-
- `searchType` — `"1"` = basic keyword, `"2"` = design code, `"3"` = owner name
|
|
58
|
-
- `statusType` — `"A"` = active/live only, `"D"` = dead only, `""` = all
|
|
59
|
-
- `pluralVariants` — `true` to include plural variations
|
|
60
|
-
- `start` — pagination offset (0-indexed)
|
|
61
|
-
- `rows` — results per page (max 500)
|
|
62
|
-
|
|
63
|
-
### Alternative: GET search
|
|
54
|
+
Serial numbers are 8 digits (no dashes). Example:
|
|
64
55
|
|
|
65
|
-
```
|
|
66
|
-
|
|
56
|
+
```bash
|
|
57
|
+
curl -s "https://tmsearch.uspto.gov/tsdr-api-v1-0-0/tsdr-api?serialNumber=78787878" \
|
|
58
|
+
-H "Accept: application/json"
|
|
67
59
|
```
|
|
68
60
|
|
|
69
|
-
### Response
|
|
61
|
+
### Response Structure
|
|
70
62
|
|
|
71
63
|
```json
|
|
72
64
|
{
|
|
73
|
-
"
|
|
74
|
-
|
|
65
|
+
"metadata": {
|
|
66
|
+
"caseStatus": "Abandoned because the applicant failed to respond...",
|
|
67
|
+
"statusDate": "2007-09-25",
|
|
68
|
+
"owners": [
|
|
69
|
+
{
|
|
70
|
+
"ipInfo": {
|
|
71
|
+
"name": "OWNER NAME",
|
|
72
|
+
"legalEntity": "3",
|
|
73
|
+
"contactAddress": {
|
|
74
|
+
"mailingAddresses": [
|
|
75
|
+
{
|
|
76
|
+
"cityName": "City",
|
|
77
|
+
"geographicRegionName": "STATE",
|
|
78
|
+
"postalCode": "12345",
|
|
79
|
+
"countryName": "UNITED STATES OF AMERICA"
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
},
|
|
83
|
+
"citizenship": {
|
|
84
|
+
"countryName": "UNITED STATES OF AMERICA",
|
|
85
|
+
"geographicRegionName": "STATE"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
],
|
|
90
|
+
"attorney": {
|
|
91
|
+
"ipInfo": { "name": "Attorney Name" }
|
|
92
|
+
},
|
|
93
|
+
"correspondent": {
|
|
94
|
+
"ipInfo": {
|
|
95
|
+
"name": "Correspondent Name",
|
|
96
|
+
"contactAddress": { "mailingAddresses": [...], "electronicAddresses": [...] }
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
"markDetails": {
|
|
100
|
+
"isStandardCharClaimed": false
|
|
101
|
+
},
|
|
102
|
+
"tm5Status": {
|
|
103
|
+
"tm5StatusDescription": "...",
|
|
104
|
+
"tm5StatusCode": "10",
|
|
105
|
+
"tm5StatusDescriptor": "DEAD/APPLICATION/Refused/Dismissed or Invalidated",
|
|
106
|
+
"tm5LiveDead": "dead"
|
|
107
|
+
},
|
|
108
|
+
"classes": [
|
|
109
|
+
{ "classNumber": "009", "firstUseAnywhereDate": null, "firstUseInCommerceDate": null }
|
|
110
|
+
],
|
|
111
|
+
"docketNumber": "..."
|
|
112
|
+
},
|
|
113
|
+
"maintenance": {},
|
|
114
|
+
"prosecutionHistory": [
|
|
75
115
|
{
|
|
76
|
-
"
|
|
77
|
-
"
|
|
78
|
-
"
|
|
79
|
-
"status": "Live/Registered",
|
|
80
|
-
"statusCode": "A",
|
|
81
|
-
"filingDate": "1997-03-15",
|
|
82
|
-
"registrationDate": "1999-08-17",
|
|
83
|
-
"owner": "Apple Inc.",
|
|
84
|
-
"ownerAddress": "Cupertino, CALIFORNIA, UNITED STATES",
|
|
85
|
-
"internationalClassification": ["009", "042"],
|
|
86
|
-
"goodsServices": "Computers, computer software...",
|
|
87
|
-
"attorney": "...",
|
|
88
|
-
"markDrawingCode": "4"
|
|
116
|
+
"historyDate": "2026-03-06",
|
|
117
|
+
"historyDescription": "Amended Drawing",
|
|
118
|
+
"documentId": "https://tsdr.uspto.gov/documentviewer?caseId=sn78787878&docId=..."
|
|
89
119
|
}
|
|
90
|
-
]
|
|
120
|
+
],
|
|
121
|
+
"assignments": [...],
|
|
122
|
+
"proceedings": [...],
|
|
123
|
+
"international": {}
|
|
91
124
|
}
|
|
92
125
|
```
|
|
93
126
|
|
|
94
|
-
|
|
95
|
-
> returns errors, fall back to scraping `https://tmsearch.uspto.gov/search/search-information` or
|
|
96
|
-
> use the TSDR API below. See `references/scraping-fallback.md` for the web scraping approach.
|
|
127
|
+
### Key Response Fields
|
|
97
128
|
|
|
98
|
-
|
|
129
|
+
| Path | Description |
|
|
130
|
+
|---|---|
|
|
131
|
+
| `metadata.caseStatus` | Human-readable current status |
|
|
132
|
+
| `metadata.statusDate` | Date of last status change |
|
|
133
|
+
| `metadata.owners[].ipInfo.name` | Owner/applicant name |
|
|
134
|
+
| `metadata.owners[].ipInfo.contactAddress` | Owner address |
|
|
135
|
+
| `metadata.attorney.ipInfo.name` | Attorney of record |
|
|
136
|
+
| `metadata.tm5Status.tm5LiveDead` | `"live"` or `"dead"` |
|
|
137
|
+
| `metadata.tm5Status.tm5StatusDescriptor` | Structured status (e.g., `"LIVE/REGISTRATION/Registered"`) |
|
|
138
|
+
| `metadata.classes[].classNumber` | Nice Classification codes |
|
|
139
|
+
| `metadata.markDetails.isStandardCharClaimed` | Whether it's a standard character mark |
|
|
140
|
+
| `prosecutionHistory[]` | Timeline of case events with document links |
|
|
141
|
+
|
|
142
|
+
> **Note:** This API does NOT return the word mark text itself. To get the mark text, you need
|
|
143
|
+
> the keyword search approach (browser automation or RapidAPI).
|
|
99
144
|
|
|
100
|
-
|
|
145
|
+
---
|
|
101
146
|
|
|
102
|
-
|
|
147
|
+
## API 2: TSDR Bulk API (Requires API key — XML)
|
|
103
148
|
|
|
104
|
-
|
|
149
|
+
The original TSDR API at `tsdrapi.uspto.gov` now **requires an API key for all requests** (changed
|
|
150
|
+
October 2024). Register at https://account.uspto.gov/api-manager/.
|
|
105
151
|
|
|
106
|
-
###
|
|
152
|
+
### Endpoints
|
|
107
153
|
|
|
108
154
|
```bash
|
|
109
|
-
# Case status
|
|
110
|
-
GET https://tsdrapi.uspto.gov/ts/cd/casestatus/sn{SERIAL_NUMBER}/content.html
|
|
111
|
-
|
|
112
|
-
# Case status as XML (machine-readable)
|
|
155
|
+
# Case status as XML (requires API key)
|
|
113
156
|
GET https://tsdrapi.uspto.gov/ts/cd/casestatus/sn{SERIAL_NUMBER}/info.xml
|
|
157
|
+
Header: USPTO-API-KEY: YOUR_KEY
|
|
158
|
+
|
|
159
|
+
# Case status as HTML
|
|
160
|
+
GET https://tsdrapi.uspto.gov/ts/cd/casestatus/sn{SERIAL_NUMBER}/content.html
|
|
161
|
+
Header: USPTO-API-KEY: YOUR_KEY
|
|
114
162
|
|
|
115
|
-
#
|
|
163
|
+
# By registration number
|
|
116
164
|
GET https://tsdrapi.uspto.gov/ts/cd/casestatus/rn{REG_NUMBER}/info.xml
|
|
117
165
|
|
|
118
|
-
# Case documents
|
|
166
|
+
# Case documents PDF bundle
|
|
119
167
|
GET https://tsdrapi.uspto.gov/ts/cd/casedocs/bundle.pdf?sn={SERIAL_NUMBER}
|
|
120
168
|
|
|
121
169
|
# Raw trademark image
|
|
122
170
|
GET https://tsdrapi.uspto.gov/ts/cd/rawImage/{SERIAL_NUMBER}
|
|
123
171
|
```
|
|
124
172
|
|
|
125
|
-
|
|
173
|
+
Rate limit: **60 requests/minute per API key**.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Keyword Search via Browser Automation (Recommended)
|
|
178
|
+
|
|
179
|
+
Since the tmsearch.uspto.gov search backend is protected by AWS WAF, use Playwright to drive
|
|
180
|
+
the web UI and intercept API responses.
|
|
181
|
+
|
|
182
|
+
**Important:** The AWS WAF bot detection is non-deterministic — headless browsers are blocked
|
|
183
|
+
intermittently. Use anti-detection settings and retries. Even with these, keyword search may
|
|
184
|
+
fail occasionally. The RapidAPI wrapper (below) is more reliable if you need consistent results.
|
|
185
|
+
|
|
186
|
+
```python
|
|
187
|
+
from playwright.sync_api import sync_playwright
|
|
188
|
+
|
|
189
|
+
def search_trademark(keyword: str, max_results: int = 25) -> dict:
|
|
190
|
+
"""Search USPTO trademarks by keyword using browser automation."""
|
|
191
|
+
results = {"totalFound": 0, "trademarks": []}
|
|
192
|
+
|
|
193
|
+
with sync_playwright() as p:
|
|
194
|
+
# Anti-detection settings to bypass AWS WAF
|
|
195
|
+
browser = p.chromium.launch(
|
|
196
|
+
headless=True,
|
|
197
|
+
args=["--disable-blink-features=AutomationControlled"],
|
|
198
|
+
)
|
|
199
|
+
context = browser.new_context(
|
|
200
|
+
user_agent=(
|
|
201
|
+
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
|
|
202
|
+
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
|
203
|
+
"Chrome/120.0.0.0 Safari/537.36"
|
|
204
|
+
),
|
|
205
|
+
viewport={"width": 1920, "height": 1080},
|
|
206
|
+
)
|
|
207
|
+
page = context.new_page()
|
|
208
|
+
page.add_init_script(
|
|
209
|
+
'Object.defineProperty(navigator, "webdriver", {get: () => undefined})'
|
|
210
|
+
)
|
|
211
|
+
|
|
212
|
+
# Intercept the Elasticsearch API responses
|
|
213
|
+
def handle_response(response):
|
|
214
|
+
if "prod-stage" in response.url and response.status == 200:
|
|
215
|
+
try:
|
|
216
|
+
data = response.json()
|
|
217
|
+
if isinstance(data, dict) and "hits" in data:
|
|
218
|
+
hits = data.get("hits", {})
|
|
219
|
+
total = hits.get("total", {})
|
|
220
|
+
results["totalFound"] = total.get("value", 0) if isinstance(total, dict) else total
|
|
221
|
+
for hit in hits.get("hits", [])[:max_results]:
|
|
222
|
+
results["trademarks"].append(hit.get("_source", {}))
|
|
223
|
+
except Exception:
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
page.on("response", handle_response)
|
|
227
|
+
page.goto("https://tmsearch.uspto.gov/search/search-information", timeout=30000)
|
|
228
|
+
page.wait_for_load_state("networkidle")
|
|
229
|
+
page.wait_for_timeout(2000) # Wait for WAF challenge to resolve
|
|
230
|
+
|
|
231
|
+
# Type keyword and submit
|
|
232
|
+
search_input = page.locator('input[type="text"]').first
|
|
233
|
+
search_input.fill(keyword.upper(), timeout=10000)
|
|
234
|
+
search_input.press("Enter")
|
|
235
|
+
|
|
236
|
+
# Wait for results (longer wait needed for WAF + async results)
|
|
237
|
+
page.wait_for_timeout(6000)
|
|
238
|
+
|
|
239
|
+
browser.close()
|
|
240
|
+
|
|
241
|
+
return results
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
### Install Playwright
|
|
245
|
+
|
|
246
|
+
```bash
|
|
247
|
+
pip install playwright
|
|
248
|
+
playwright install chromium
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## Keyword Search via RapidAPI (Alternative — requires API key)
|
|
254
|
+
|
|
255
|
+
If browser automation is not practical, the RapidAPI unofficial USPTO wrapper provides reliable
|
|
256
|
+
keyword search.
|
|
126
257
|
|
|
127
|
-
|
|
128
|
-
- Add key as header: `USPTO-API-KEY: YOUR_KEY_HERE`
|
|
129
|
-
- Rate limit: **60 requests/minute per API key**
|
|
258
|
+
**Sign up:** https://rapidapi.com/pentium10/api/uspto-trademark
|
|
130
259
|
|
|
131
260
|
```bash
|
|
132
|
-
|
|
133
|
-
|
|
261
|
+
# Keyword search (active marks)
|
|
262
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/trademarkSearch/APPLE/active" \
|
|
263
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
264
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
265
|
+
|
|
266
|
+
# Availability check
|
|
267
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/trademarkAvailable/CLOUDPEAK" \
|
|
268
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
269
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
270
|
+
|
|
271
|
+
# Search by owner
|
|
272
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/ownerSearch/Apple%20Inc/" \
|
|
273
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
274
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
275
|
+
|
|
276
|
+
# Lookup by serial number
|
|
277
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/serialSearch/78787878" \
|
|
278
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
279
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
280
|
+
|
|
281
|
+
# Batch search (POST)
|
|
282
|
+
curl -X POST "https://uspto-trademark.p.rapidapi.com/v1/batchTrademarkSearch" \
|
|
283
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
284
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY" \
|
|
285
|
+
-H "Content-Type: application/json" \
|
|
286
|
+
-d '{"keywords": ["CLOUDPEAK", "SKYBRIDGE", "NEONPULSE"]}'
|
|
134
287
|
```
|
|
135
288
|
|
|
289
|
+
RapidAPI endpoints:
|
|
290
|
+
- `/v1/trademarkSearch/{keyword}/{status}` — keyword search (`active`, `dead`, or `all`)
|
|
291
|
+
- `/v1/trademarkAvailable/{keyword}` — simple yes/no availability
|
|
292
|
+
- `/v1/ownerSearch/{owner_name}/{postcode}` — search by owner
|
|
293
|
+
- `/v1/serialSearch/{serial_number}` — lookup by serial number
|
|
294
|
+
- `/v1/batchTrademarkSearch` — multiple keywords (POST)
|
|
295
|
+
|
|
136
296
|
---
|
|
137
297
|
|
|
138
298
|
## CLI Tool Implementation (tm-search)
|
|
@@ -142,11 +302,11 @@ When building the `tm-search` command-line tool, follow this structure:
|
|
|
142
302
|
### Core Commands
|
|
143
303
|
|
|
144
304
|
```bash
|
|
145
|
-
tm-search keyword <word> # Search by keyword
|
|
305
|
+
tm-search keyword <word> # Search by keyword (uses Playwright)
|
|
146
306
|
tm-search keyword <word> --status=A # Active trademarks only
|
|
147
307
|
tm-search keyword <word> --status=D # Dead trademarks only
|
|
148
308
|
tm-search available <word> # Check if word is available (not registered live)
|
|
149
|
-
tm-search status <serial_number> # Lookup by serial number
|
|
309
|
+
tm-search status <serial_number> # Lookup by serial number (uses TSDR API)
|
|
150
310
|
tm-search batch <word1,word2,...> # Check multiple words
|
|
151
311
|
tm-search validate <file.txt> # Validate words from a file (one per line)
|
|
152
312
|
```
|
|
@@ -177,58 +337,34 @@ Top matches:
|
|
|
177
337
|
A keyword is considered **AVAILABLE** if there are zero live/active marks with exact OR confusingly
|
|
178
338
|
similar text. The agent should:
|
|
179
339
|
|
|
180
|
-
1. Search exact keyword
|
|
340
|
+
1. Search exact keyword (via Playwright or RapidAPI)
|
|
181
341
|
2. If results > 0 → **LIKELY REGISTERED** — show matches
|
|
182
342
|
3. If results == 0 → **LIKELY AVAILABLE** — note this is not legal advice
|
|
183
343
|
4. Always caveat: suggest professional trademark attorney review before filing
|
|
184
344
|
|
|
185
|
-
```python
|
|
186
|
-
def check_availability(keyword):
|
|
187
|
-
results = search_trademark(keyword, status="A")
|
|
188
|
-
if results["totalFound"] == 0:
|
|
189
|
-
return "LIKELY AVAILABLE"
|
|
190
|
-
else:
|
|
191
|
-
return f"LIKELY TAKEN ({results['totalFound']} active marks)"
|
|
192
|
-
```
|
|
193
|
-
|
|
194
345
|
---
|
|
195
346
|
|
|
196
347
|
## Batch Validation
|
|
197
348
|
|
|
198
|
-
For validating a list of keywords
|
|
199
|
-
|
|
200
|
-
```python
|
|
201
|
-
words = ["CloudPeak", "SkyBridge", "NeonPulse"]
|
|
202
|
-
results = []
|
|
203
|
-
for word in words:
|
|
204
|
-
r = search_trademark(word.upper(), status="A")
|
|
205
|
-
results.append({
|
|
206
|
-
"keyword": word,
|
|
207
|
-
"status": "AVAILABLE" if r["totalFound"] == 0 else "TAKEN",
|
|
208
|
-
"count": r["totalFound"]
|
|
209
|
-
})
|
|
210
|
-
# Output as table or CSV
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
Rate-limit: Add 0.5–1s delay between requests to avoid throttling.
|
|
349
|
+
For validating a list of keywords, add a 2–3 second delay between Playwright searches to avoid
|
|
350
|
+
triggering rate limits. With RapidAPI, 0.5–1s delay is sufficient.
|
|
214
351
|
|
|
215
352
|
---
|
|
216
353
|
|
|
217
354
|
## Implementation Notes
|
|
218
355
|
|
|
219
|
-
- The `tmsearch.uspto.gov`
|
|
356
|
+
- The `tmsearch.uspto.gov` search backend is protected by **AWS WAF** — direct HTTP keyword search does not work
|
|
357
|
+
- The TSDR Details API (`/tsdr-api-v1-0-0/tsdr-api?serialNumber=...`) works without auth and returns JSON
|
|
358
|
+
- The old TSDR XML API (`tsdrapi.uspto.gov`) requires an **API key for all requests** since October 2024
|
|
220
359
|
- Always **uppercase** keywords before searching (USPTO stores marks in uppercase)
|
|
221
|
-
- Include `User-Agent` header to avoid bot detection: `"Mozilla/5.0 (compatible; tm-search/1.0)"`
|
|
222
|
-
- For `pluralVariants=true`, USPTO auto-expands COFFEE → COFFEES, etc.
|
|
223
360
|
- International Classification (Nice Classification) codes define goods/services category
|
|
224
361
|
- Serial numbers are 8 digits; Registration numbers are 7 digits
|
|
225
362
|
|
|
226
363
|
## Reference Files
|
|
227
364
|
|
|
228
365
|
- `references/field-guide.md` — Full field descriptions and Nice Classification codes
|
|
229
|
-
- `references/scraping-fallback.md` —
|
|
366
|
+
- `references/scraping-fallback.md` — Browser automation fallback details
|
|
230
367
|
- `scripts/tm_search.py` — Ready-to-use Python implementation
|
|
231
|
-
- `scripts/tm_validate.py` — Batch validation script
|
|
232
368
|
|
|
233
369
|
---
|
|
234
370
|
|
|
@@ -237,4 +373,4 @@ Rate-limit: Add 0.5–1s delay between requests to avoid throttling.
|
|
|
237
373
|
Always include when providing availability results:
|
|
238
374
|
> "This is a preliminary search only. Trademark availability is complex and depends on many
|
|
239
375
|
> factors including similar marks, geographic use, and goods/services classification. Consult a
|
|
240
|
-
> licensed trademark attorney before filing."
|
|
376
|
+
> licensed trademark attorney before filing."
|
|
@@ -1,135 +1,100 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Browser Automation Fallback for tmsearch.uspto.gov
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The tmsearch.uspto.gov search backend uses an Elasticsearch API at
|
|
4
|
+
`https://tmsearch.uspto.gov/prod-stage-v1-0-0/` but it is protected by AWS WAF bot detection.
|
|
5
|
+
Direct HTTP requests (curl, requests, fetch) return `403` or `Missing Authentication Token`.
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Browser automation is the only reliable way to perform keyword searches programmatically.
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
If the documented endpoints in SKILL.md fail, use browser DevTools (Network tab) on
|
|
9
|
-
https://tmsearch.uspto.gov/search/search-information to intercept the actual XHR/fetch requests
|
|
10
|
-
being made, then replicate those in code.
|
|
9
|
+
## Why Direct HTTP Doesn't Work
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
The site's `configuration.json` reveals:
|
|
12
|
+
- Search backend: `https://tmsearch.uspto.gov/prod-stage-v1-0-0/`
|
|
13
|
+
- WAF challenge script: loaded dynamically from `awsWafChallengeUrl`
|
|
14
|
+
- The browser must solve the WAF challenge to get a token that's sent with API requests
|
|
13
15
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
import time
|
|
17
|
-
|
|
18
|
-
HEADERS = {
|
|
19
|
-
"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36",
|
|
20
|
-
"Accept": "application/json, text/plain, */*",
|
|
21
|
-
"Accept-Language": "en-US,en;q=0.9",
|
|
22
|
-
"Referer": "https://tmsearch.uspto.gov/search/search-information",
|
|
23
|
-
"Origin": "https://tmsearch.uspto.gov",
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
def search_trademark_web(keyword: str, status: str = "A", rows: int = 25) -> dict:
|
|
27
|
-
"""
|
|
28
|
-
Search USPTO trademark database.
|
|
29
|
-
status: "A" = active, "D" = dead, "" = all
|
|
30
|
-
"""
|
|
31
|
-
session = requests.Session()
|
|
32
|
-
|
|
33
|
-
# First GET the main page to get any session cookies
|
|
34
|
-
session.get("https://tmsearch.uspto.gov/search/search-information", headers=HEADERS)
|
|
35
|
-
|
|
36
|
-
# Attempt POST to backend
|
|
37
|
-
payload = {
|
|
38
|
-
"keyword": keyword.upper(),
|
|
39
|
-
"searchType": "1",
|
|
40
|
-
"statusType": status,
|
|
41
|
-
"pluralVariants": False,
|
|
42
|
-
"start": 0,
|
|
43
|
-
"rows": rows
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
response = session.post(
|
|
47
|
-
"https://tmsearch.uspto.gov/search/keyword",
|
|
48
|
-
json=payload,
|
|
49
|
-
headers=HEADERS,
|
|
50
|
-
timeout=30
|
|
51
|
-
)
|
|
52
|
-
|
|
53
|
-
if response.status_code == 200:
|
|
54
|
-
return response.json()
|
|
55
|
-
|
|
56
|
-
# If POST fails, try GET
|
|
57
|
-
params = {
|
|
58
|
-
"keyword": keyword.upper(),
|
|
59
|
-
"statusType": status,
|
|
60
|
-
"rows": rows,
|
|
61
|
-
"start": 0
|
|
62
|
-
}
|
|
63
|
-
response = session.get(
|
|
64
|
-
"https://tmsearch.uspto.gov/search/keyword",
|
|
65
|
-
params=params,
|
|
66
|
-
headers=HEADERS,
|
|
67
|
-
timeout=30
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
return response.json()
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Selenium/Playwright Approach (Last Resort)
|
|
16
|
+
Any attempt to call the Elasticsearch endpoint directly will fail because the WAF token
|
|
17
|
+
is missing from the request.
|
|
74
18
|
|
|
75
|
-
|
|
19
|
+
## Playwright Approach (Recommended)
|
|
76
20
|
|
|
77
21
|
```python
|
|
78
22
|
from playwright.sync_api import sync_playwright
|
|
79
23
|
import json
|
|
80
24
|
|
|
81
|
-
def
|
|
25
|
+
def search_trademark(keyword: str, max_results: int = 25) -> dict:
|
|
26
|
+
"""Search USPTO trademarks by keyword using browser automation."""
|
|
27
|
+
results = {"totalFound": 0, "trademarks": []}
|
|
28
|
+
|
|
82
29
|
with sync_playwright() as p:
|
|
83
30
|
browser = p.chromium.launch(headless=True)
|
|
84
31
|
page = browser.new_page()
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
# Intercept API responses
|
|
32
|
+
|
|
88
33
|
def handle_response(response):
|
|
89
|
-
if "
|
|
34
|
+
if "prod-stage" in response.url and response.status == 200:
|
|
90
35
|
try:
|
|
91
36
|
data = response.json()
|
|
92
|
-
if "
|
|
93
|
-
|
|
94
|
-
|
|
37
|
+
if isinstance(data, dict) and "hits" in data:
|
|
38
|
+
hits = data.get("hits", {})
|
|
39
|
+
total = hits.get("total", {})
|
|
40
|
+
results["totalFound"] = total.get("value", 0) if isinstance(total, dict) else total
|
|
41
|
+
for hit in hits.get("hits", [])[:max_results]:
|
|
42
|
+
results["trademarks"].append(hit.get("_source", {}))
|
|
43
|
+
except Exception:
|
|
95
44
|
pass
|
|
96
|
-
|
|
45
|
+
|
|
97
46
|
page.on("response", handle_response)
|
|
98
47
|
page.goto("https://tmsearch.uspto.gov/search/search-information")
|
|
99
|
-
|
|
100
|
-
# Fill in search form
|
|
101
|
-
page.fill('input[placeholder*="search"]', keyword)
|
|
102
|
-
page.click('button[type="submit"]')
|
|
103
48
|
page.wait_for_load_state("networkidle")
|
|
104
|
-
|
|
49
|
+
|
|
50
|
+
search_input = page.locator('input[type="text"]').first
|
|
51
|
+
search_input.fill(keyword.upper())
|
|
52
|
+
search_input.press("Enter")
|
|
53
|
+
|
|
54
|
+
page.wait_for_load_state("networkidle")
|
|
55
|
+
page.wait_for_timeout(3000)
|
|
56
|
+
|
|
105
57
|
browser.close()
|
|
106
|
-
|
|
58
|
+
|
|
59
|
+
return results
|
|
107
60
|
```
|
|
108
61
|
|
|
109
62
|
## Install Playwright
|
|
63
|
+
|
|
110
64
|
```bash
|
|
111
65
|
pip install playwright
|
|
112
66
|
playwright install chromium
|
|
113
67
|
```
|
|
114
68
|
|
|
115
|
-
##
|
|
69
|
+
## TSDR Details API (No browser needed)
|
|
70
|
+
|
|
71
|
+
For looking up a single trademark by serial number, the TSDR Details API works with plain HTTP:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
curl -s "https://tmsearch.uspto.gov/tsdr-api-v1-0-0/tsdr-api?serialNumber=78787878" \
|
|
75
|
+
-H "Accept: application/json"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
This returns JSON with case status, owner info, classes, prosecution history, etc.
|
|
79
|
+
|
|
80
|
+
## Alternative: RapidAPI Wrapper
|
|
116
81
|
|
|
117
|
-
If
|
|
82
|
+
If browser automation is not practical, the RapidAPI unofficial wrapper provides reliable
|
|
83
|
+
keyword search with a simple REST API:
|
|
118
84
|
|
|
119
85
|
```bash
|
|
120
86
|
# Endpoint: https://uspto-trademark.p.rapidapi.com
|
|
121
87
|
# Requires: RapidAPI key (freemium plan available)
|
|
122
88
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
89
|
+
# Keyword search
|
|
90
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/trademarkSearch/APPLE/active" \
|
|
91
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
92
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
127
93
|
|
|
128
94
|
# Availability check
|
|
129
|
-
curl
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
--header "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
95
|
+
curl "https://uspto-trademark.p.rapidapi.com/v1/trademarkAvailable/CLOUDPEAK" \
|
|
96
|
+
-H "x-rapidapi-host: uspto-trademark.p.rapidapi.com" \
|
|
97
|
+
-H "x-rapidapi-key: YOUR_RAPIDAPI_KEY"
|
|
133
98
|
```
|
|
134
99
|
|
|
135
100
|
RapidAPI wrapper endpoints:
|
|
@@ -137,4 +102,4 @@ RapidAPI wrapper endpoints:
|
|
|
137
102
|
- `/v1/trademarkAvailable/{keyword}` — simple yes/no availability
|
|
138
103
|
- `/v1/ownerSearch/{owner_name}/{postcode}` — search by owner
|
|
139
104
|
- `/v1/serialSearch/{serial_number}` — lookup by serial number
|
|
140
|
-
- `/v1/batchTrademarkSearch` — multiple keywords (POST)
|
|
105
|
+
- `/v1/batchTrademarkSearch` — multiple keywords (POST)
|