The hairball page that broke your last vendor.
Some sites are weird enough that no API will ever cover them out of the box. We build custom extractors for those: managed, monitored, and billed in the same credit pool. You get a stable JSON shape; we handle the rot.
POST /custom/yelp_business_v3
{
"url": "https://yelp.com/biz/sunset-grill",
"fields":["hours","menu","photos","reviews_summary"]
}
→ 200 OK · 8 credits · 1.7s
{
"name": "Sunset Grill",
"hours": { "mon":[...], "tue":[...], ... },
"menu": [{ "section":"Mains", "items":[...] }],
"photos":["https://s3.../1.jpg", ...],
"reviews_summary": {
"rating": 4.4, "count": 1283,
"themes": ["service","brunch","seating"]
}
}
Send us a sample URL and a target schema. Within two weeks you get a stable endpoint that returns exactly that shape, every time.
When the target redesigns, we fix it, usually within hours, behind the scenes. Your endpoint stays alive; you don't need to know.
Custom extractors live at /custom/{id} and bill from your existing credit pool. No new SDK, no new contract.
Every response conforms to the schema we agreed on. Breaking changes get a version bump (yelp_business_v4); v3 stays alive for 90 days.
If the target shows different content per region, we expose geo as a parameter and run from clean residential IPs in that region.
Some extractors involve proprietary data sources or partner agreements. We work under NDA and don't advertise the targets we cover.
Copy. Paste. Ship.
const { data } = await uj.custom("yelp_business_v3", {
url: "https://yelp.com/biz/sunset-grill",
fields: ["hours","menu","photos","reviews_summary"]
});
console.log(data.reviews_summary.rating); // 4.4
// v3 returns the schema you signed off on.
// v4 may add fields or restructure; opt in.
const v3 = await uj.custom("yelp_business_v3", { url });
const v4 = await uj.custom("yelp_business_v4", { url });
// v3 stays alive for 90 days after v4 ships.
const list = await uj.customExtractors();
// [
// { id: "yelp_business_v3", credits: 8, p50: "1.7s" },
// { id: "linkedin_company_v2", credits: 12, p50: "2.3s" },
// { id: "amazon_review_pages_v1", credits: 20, p50: "3.1s" }
// ]
// For batch jobs, we deliver via webhook
const job = await uj.customBatch("yelp_business_v3", {
urls: [...100k_urls],
webhook: "https://your-app.com/ingest"
});
// Results stream as they finish; rate-limited
// to your plan's concurrency.
Real things real teams shipped this quarter.
You've tried AI Scraper and ChatGPT scraper. The target is too weird, too gated, too important to leave to a fragile prompt. Custom is the answer.
A real-estate aggregator tracks 40 portals. We build an extractor per portal that all return the same listing schema. The aggregator's code stays simple.
Some buyers need contractual SLAs and named extractors in their MSA. We package those into Custom contracts with quarterly business reviews.
A custom extractor is a fraction of the cost of a contract scraper, and we own maintenance forever. The math works in our favor by month 3.
Ship Custom Extractors tonight.
5,000 credits free. No card. Real residential proxies on the free tier.