Schematron
Extract clean, typed JSON from messy HTML with the schema-guided Schematron models.
Schematron is a family of long-context models trained to extract clean, typed JSON from messy HTML. They're built for web scraping, product data ingestion, and converting arbitrary pages into structured data: you pass a schema, and the model returns conforming JSON.
Schematron V2 Small delivers the highest extraction quality, approaching frontier-model accuracy on complex schemas. Schematron V2 Turbo is optimized for throughput and cost, processing pages significantly faster while still exceeding the quality of the previous-generation Schematron 3B. Both models handle long HTML inputs with strict schema adherence.
To learn how Schematron was trained and what it can do, see the announcement blog post.
Quickstart
Highest extraction quality for complex schemas and long pages.
Optimized for maximum throughput and lowest cost at scale.
End-to-end company scraping walkthrough using Schematron.
Extract from HTML into a typed model
Define your schema with a typed model (for example Pydantic or Zod). Pass the model's JSON Schema and the raw HTML to the model, enable JSON mode, and validate the response.
import OpenAI from "openai";
import { z } from "zod";
import { zodResponseFormat } from "openai/helpers/zod";
const openai = new OpenAI({
baseURL: "https://api.inference.net/v1",
apiKey: process.env.INFERENCE_API_KEY,
});
// 1) Define your schema (nested data and lists are supported)
const Product = z.object({
name: z.string(),
price: z.number().describe("Primary price of the product."),
specs: z.record(z.string()).describe("Specs of the product."),
tags: z.array(z.string()).describe("Tags assigned of the product."),
});
// 2) Messy HTML (could be the full page; trim to the relevant region when possible)
const html = `
<div id="item">
<h2 class="title">MacBook Pro M3</h2>
<p>Price: <b>$2,499.99</b> USD</p>
<ul info>
<li>RAM: 16GB</li>
<li>Storage: 512GB SSD</li>
</ul>
<span class="tag">laptop</span>
<span class="tag">professional</span>
<span class="tag">macbook</span>
<span class="tag">apple</span>
</div>
`;
// 3) Chat Completions extraction (typed validation)
const resp = await openai.chat.completions.parse({
model: "inference-net/schematron-v2-small",
messages: [{ role: "user", content: html }],
response_format: zodResponseFormat(Product, "product"),
});
console.log(resp.choices[0].message.content);Output
For the HTML above, Schematron produces strictly valid JSON that conforms to your schema. A representative output:
{
"name": "MacBook Pro M3",
"price": 2499.99,
"specs": {
"RAM": "16GB",
"Storage": "512GB SSD"
},
"tags": ["laptop", "professional", "macbook", "apple"]
}Best practices
- Keep temperature at zero. The model is trained to perform best at temperature 0.
- Provide a clear schema. Pass a JSON Schema or typed model (for example
Product.model_json_schema()). Include required fields and types, and optionally describe them directly in the schema (supported by Pydantic and Zod). For example:
const Product = z.object({
name: z.string().describe("Exact product name as shown in the title or primary heading."),
price: z.number().describe("Primary price of the product."),
specs: z
.object({
ram: z.string().describe("RAM capacity."),
storage: z.string().describe("Storage capacity and type."),
})
.describe("Key attributes describing the product."),
});- Pre-clean HTML (recommended). Remove scripts, styles, and boilerplate to
improve accuracy and reduce tokens. See Preprocess HTML.
Alternatives (Readability, Trafilatura, BeautifulSoup, regex) are fine;
lxmlaligns with training. - Validate on ingest. Parse with Pydantic (or your validator) and handle validation errors explicitly. Schematron should always return valid JSON matching your schema, but validating the response is still a good idea.
Preprocess HTML
Schematron models were trained on HTML pre-cleaned with
lxml.html.clean.Cleaner to strip scripts, styles, and inline JavaScript.
Matching your preprocessing to training typically improves extraction quality
and consistency.
import lxml.html as LH
from lxml.html.clean import Cleaner
HTML_CLEANER = Cleaner(
scripts=True,
javascript=True,
style=True,
inline_style=True,
safe_attrs_only=False,
)
def strip_noise(html: str) -> str:
"""Remove scripts, styles, and JavaScript from HTML using lxml."""
if not html or not html.strip():
return ""
try:
doc = LH.fromstring(html)
cleaned = HTML_CLEANER.clean_html(doc)
return LH.tostring(cleaned, encoding="unicode")
except Exception:
return ""Notes:
- You don't have to use
lxml. Alternatives like Readability (often more aggressive), Trafilatura, BeautifulSoup, or targeted regex can be acceptable. - Use whichever tool fits your content;
lxmlis recommended for this model because it matches how the training data was preprocessed.
Capabilities
Key features
- Schema-first extraction: drive output with your own JSON Schema or a typed model (for example Pydantic) and get strictly formatted JSON back.
- Long-context HTML: trained for long documents with up to 128K-token context, and robust to noisy markup.
- Strict JSON mode: 100% schema adherence.
- Cost-efficient quality: matches the quality of frontier models at a significantly lower cost.
Models
| Model ID | Best for |
|---|---|
inference-net/schematron-v2-small | Best quality for complex schemas or long pages |
inference-net/schematron-v2-turbo | Maximum throughput and lowest cost at scale |
See pricing and limits on the Schematron V2 Small and Schematron V2 Turbo model pages.
Process at scale
For large-scale extraction, use the asynchronous APIs:
Submit up to 1,000,000 extraction requests in one JSONL file, track their status asynchronously, and get an optional webhook within a 24-hour window.
Send smaller groups (up to 50 requests) in one JSON payload, follow the group as a single job, and get one callback when everything is done.
Limitations
- Context window: up to 128K tokens per request. Truncate or chunk very large pages.
- Ambiguous fields: if a field requires summarization or synthesis, make your schema and field descriptions explicit about what you expect. Schematron does not take a prompt or directions; all information goes through the schema.
Legacy models
Support
For technical support, email support@inference.net or schedule a call.