cd /news/structured-data/prompt-based-vs-schema-based-extract… · home › topics › structured-data › article
[ARTICLE · art-159694] src=spidra.io ↗ pub= topic=structured-data verified=true sentiment=· neutral

Prompt-based vs schema-based extraction: Which is more reliable?

A Spidra comparison of prompt-based versus schema-based extraction found that natural-language prompts alone can pull structured data from job postings, but a JSON Schema is what guarantees a response an application can reliably consume. The test ran both approaches through Spidra's Scrape API against three Python.org job board postings — an AI Engineer role requiring at least three years of experience with no stated salary, a senior engineering role specifying eight to fifteen years, and a junior machine learning role with a salary range but no minimum years — to check handling of numeric values, missing fields, and differently expressed information. The prompt instructed the model to return fields including title, company, location, posted_date, minimum_experience_years, salary, telecommuting_allowed and agencies_allowed, format dates as YYYY-MM-DD, use the lower bound of an experience range, and return null for missing information.

by read14 min views1 publishedOct 28, 2026
Prompt-based vs schema-based extraction: Which is more reliable?
Image: Spidra (auto-discovered)

A well-written prompt can extract structured data from a website without a JSON Schema. But when that data feeds an application or a recurring workflow, getting the right information isn't your only concern. You also need a response your code can reliably consume.

Prompt-based and schema-based extraction offer different ways to control that output. Prompts describe what you want in natural language, while schemas define the structure and data types your application expects.

To compare them, we'll use Spidra to extract job information from three real pages, examine the returned JSON, and see where a schema makes a difference.

Prompt-based vs schema-based extraction: What's the difference? #

Prompt-based extraction uses natural-language instructions to tell an AI model what information to collect from a page.

For example, you could provide this instruction:

Extract the job title, company, location, minimum experience, and salary. Return the results as JSON. Use null for information that isn't provided.

The model reads the page and decides how to organize the response based on those instructions. You can specify field names, data types, formats, and rules for missing information directly in the prompt.

This makes prompt-based extraction useful when you're exploring unfamiliar pages, experimenting with the fields you need, or collecting information for a one-off task.

Schema-based extraction takes a more explicit approach. Instead of describing the entire expected structure in natural language, you provide a JSON Schema defining the fields, types, and relationships in the response.

For example:

{
  "type": "object",
  "required": ["title", "salary"],
  "properties": {
    "title": {
      "type": "string"
    },
    "salary": {
      "type": ["number", "null"]
    }
  }
}

This schema describes an object containing a required title string and a required salary field that can hold either a number or null.

The distinction is that the schema explicitly defines the expected structure, while a prompt communicates that expectation through natural language.

These approaches aren't mutually exclusive. You can use a prompt to describe the information and extraction rules, then add a schema to control how the response is organized.

In Spidra, both options are available through the Scrape API. You can extract information with a prompt alone or supply a JSON Schema when you need a specific output structure.

But how much difference does the schema actually make?

Extract job data using a prompt #

Let's work with three job postings on the Python.org job board:

These postings have different information available. The AI Engineer role requires at least three years of experience but doesn't state a salary. The senior engineering role specifies eight to fifteen years of experience. The junior machine learning role includes a salary range but doesn't give a minimum number of years.

That gives us useful conditions for checking how extraction handles numeric values, missing fields, and information expressed differently across pages.

Open the Spidra dashboard, select Scrape, and enter the three URLs.

Choose JSON as the output format and provide this extraction instruction:

Extract the following information from the main job posting:
title, company, location, posted_date,
minimum_experience_years, salary,
telecommuting_allowed, and agencies_allowed.

Return a JSON object using these field names.
Format dates as YYYY-MM-DD and minimum experience
as a number. For an experience range, use the lower
bound. Preserve salary amounts, currency, and period
as stated.

Return true or false for permissions only when
explicitly stated. Use null for missing information.

Do not infer values or include related job listings.
Return JSON only.

There's no schema here. The prompt specifies the fields and formatting rules, leaving the model to organize the response.

Spidra returned the following JSON:

[
  {
    "title": "AI Engineer",
    "company": "webbyfox consultancy",
    "location": "London, UK",
    "posted_date": "2026-10-23",
    "minimum_experience_years": 3,
    "salary": null,
    "telecommuting_allowed": true,
    "agencies_allowed": true
  },
  {
    "title": "Senior Software Engineer — Python, React & AI",
    "company": "Camden Kelly Staffing",
    "location": "Rowlett, TX, United States",
    "posted_date": "2026-10-20",
    "minimum_experience_years": 8,
    "salary": null,
    "telecommuting_allowed": true,
    "agencies_allowed": false
  },
  {
    "title": "Junior Machine Learning Engineer",
    "company": "HFT Architecture",
    "location": "Remote, Worldwide",
    "posted_date": "2026-10-14",
    "minimum_experience_years": null,
    "salary": "USD 125,000–155,000 a year",
    "telecommuting_allowed": true,
    "agencies_allowed": false
  }
]

The result is already usable JSON. Every job contains the eight requested fields, the dates use a consistent format, and the experience values are numbers rather than strings.

The missing information is handled correctly, too. Salary is null for the first two jobs, while the third preserves the stated salary range. The junior role has null for minimum experience because the posting doesn't specify a number.

Running the same prompt-based extraction again returned the same structure and field values across all three postings.

That's a useful result. A well-specified prompt can produce structured, consistent data without a formal schema. For a one-off extraction, this response may be everything you need.

The question is whether you'd want to depend on that structure every time an application runs.

Extract the same data with a JSON Schema #

Now let's define the expected output structure explicitly.

Because we're collecting multiple job postings in one response, we'll use a root object containing a jobs array. Each item represents one posting.

Here's the JSON Schema:

{
  "type": "object",
  "required": ["jobs"],
  "properties": {
    "jobs": {
      "type": "array",
      "items": {
        "type": "object",
        "required": [
          "title",
          "company",
          "location",
          "posted_date",
          "minimum_experience_years",
          "salary",
          "telecommuting_allowed",
          "agencies_allowed"
        ],
        "properties": {
          "title": {"type": "string"},
          "company": {"type": "string"},
          "location": {"type": "string"},
          "posted_date": {"type": ["string", "null"]},
          "minimum_experience_years": {
            "type": ["number", "null"]
          },
          "salary": {"type": ["string", "null"]},
          "telecommuting_allowed": {
            "type": ["boolean", "null"]
          },
          "agencies_allowed": {
            "type": ["boolean", "null"]
          }
        }
      }
    }
  }
}

The schema defines which fields each record contains and what types they accept.

Notice that salary is a string rather than a number. A salary can be expressed as a range, include a currency, or specify a payment period. Since we want to preserve the information exactly as stated, a nullable string is appropriate here.

The minimum_experience_years field accepts a number or null, while the permission fields accept a boolean or null. That last distinction matters: a posting that doesn't mention telecommuting isn't necessarily saying that telecommuting is prohibited.

You can build a schema manually or use Spidra's JSON Schema Generator.

To use this in the Playground, enter the same three URLs, add the schema, and instruct Spidra to return one job record per URL inside the jobs array.

The corrected schema-based extraction returned all three records. Here are the selected fields from the response:

{
  "jobs": [
    {
      "title": "AI Engineer",
      "minimum_experience_years": 3,
      "salary": null
    },
    {
      "title": "Senior Software Engineer — Python, React & AI",
      "minimum_experience_years": 8,
      "salary": null
    },
    {
      "title": "Junior Machine Learning Engineer",
      "minimum_experience_years": null,
      "salary": "USD 125,000–155,000 a year"
    }
  ]
}

The example above displays selected fields. The full response contained all eight fields for each job.

The extracted values matched the prompt-only results.

There's one visible structural difference: prompt-only extraction returned a top-level array, while schema-based extraction returned an object with a jobs property.

Neither is inherently better. The advantage of the second structure is that we explicitly requested it, and application code can be written against that contract.

Your schema must describe the whole response

There's a detail worth understanding when extracting multiple records.

If your schema describes only a single job object, you're requesting one object even when multiple pages are supplied.

An initial schema configuration did exactly that and returned only the AI Engineer record. After the extraction instructions and schema were updated to describe a jobs array, all three records appeared.

This wasn't evidence that Spidra had failed to read the other pages. It demonstrated that the requested output structure matters.

Spidra requires the root of an extraction schema to be an object. To return a collection, define an array property within that object, as shown above.

Which approach produced more reliable results? #

Both approaches performed well on these three job postings.

Here's what the outputs showed:

Comparison Prompt-based Prompt + schema
Jobs returned 3 3
Requested fields per job 8 8
Consistent field names Yes Yes
Correct data types Yes Yes
Missing values represented as null Yes Yes
Values matched between methods Yes Yes
Explicit output contract No Yes
Response structure Top-level array Object containing jobs

The prompt-only method also returned the same results in two observed runs. The corrected schema-based request was observed once, so these results don't establish a general success rate or prove how either method behaves across hundreds of repeated extractions.

They do demonstrate something useful: adding a schema didn't improve the extracted field values in this example because the prompt-only extraction already produced the expected data.

Where the schema adds value is in defining what downstream code should receive.

Consider an application that stores job listings in a database. Its ingestion code may expect minimum_experience_years to be numeric and telecommuting_allowed to be a boolean.

If a future prompt-only response returns "3+ years" instead of 3, or changes company to company_name, the application needs to normalize the data or reject it.

A schema reduces that uncertainty by specifying the expected fields and types as part of the extraction request.

That is the main reason to prefer schema-based extraction for recurring workflows, even when prompt-only extraction works well during initial development.

Correct structure doesn't guarantee correct information #

It's tempting to treat schema-compliant JSON as verified data, but these are different things.

A schema can confirm that minimum_experience_years is a number. It cannot independently establish whether the number extracted from a job posting is correct.

If the source says five years and the extracted response contains three, both values satisfy a numeric schema.

OpenAI's Structured Outputs documentation makes the same distinction: an output can follow the requested structure and still contain mistakes.

Our job postings also demonstrate a subtler problem.

The Camden Kelly Staffing listing explicitly permits telecommuting, so Spidra correctly returned:

{
  "telecommuting_allowed": true
}

However, the same posting requires applicants to be physically located in the United States and authorized to work there.

A job platform that interprets telecommuting_allowed: true as "available to remote applicants worldwide" would therefore misclassify the position.

The extraction isn't wrong. The field simply doesn't capture every condition needed for that decision.

If your application needs to distinguish remote jobs by geographic eligibility, you should extract that information separately. For example, you might add a nullable remote_location_restrictions field and instruct the extractor to preserve any explicitly stated restrictions.

Similarly, consider the minimum experience field. The senior engineering job states an experience range of 8–15 years, but our output contains only 8 because that's what the prompt requested.

That value is correct for minimum experience, but it doesn't preserve the upper end of the range.

Neither problem is solved automatically by adding a schema. The developer must decide which facts the application needs, describe them clearly, and verify the extracted values where accuracy matters.

Reliable extraction requires both a predictable structure and values that faithfully represent the source.

Validate extracted data before using it #

A schema helps control the extraction response, but your application should still validate data before storing or processing it.

Let's take the schema-based response and add a validation step in Python.

Save the schema from the earlier example as job-schema.json and the extracted response as jobs.json. Then install the JSON Schema validation library:

pip install jsonschema

The following script validates the returned object and checks that all three expected records are present:

import json
from pathlib import Path
from jsonschema import Draft202012Validator

schema = json.loads(Path("job-schema.json").read_text())
data = json.loads(Path("jobs.json").read_text())

validator = Draft202012Validator(schema)
errors = list(validator.iter_errors(data))

if errors:
    raise ValueError(errors[0].message)

jobs = data["jobs"]

if len(jobs) != 3:
    raise ValueError("Expected three job records")

for job in jobs:
    if not job["title"].strip():
        raise ValueError("Job title cannot be empty")

The schema check validates the expected fields and types. The record-count check catches a different problem: a response containing one perfectly valid job would still satisfy the schema, but it wouldn't be complete for our three input URLs.

For a recurring workflow, the next step is to compare records against their source pages. You might verify required identifiers, detect duplicates, or review high-impact fields such as prices, eligibility conditions, and financial values.

This validation also works with prompt-only output. You can wrap its top-level array in a jobs object before checking it against the same schema.

That flexibility matters because choosing schema-based extraction doesn't eliminate application-side validation. It makes the extraction contract clearer, while application checks enforce additional requirements specific to your workflow.

When should you use prompt-based or schema-based extraction? #

The choice depends less on which method can generate JSON and more on what you're doing with the result.

Your use case Recommended approach Why
Exploring an unfamiliar website Prompt-based Easy to change fields and instructions
Extracting information for a one-off task Prompt-based A clear prompt may already produce everything you need
Feeding records into a database Prompt + schema Defines expected fields and types
Running recurring extraction jobs Prompt + schema Reduces uncertainty for downstream consumers
Extracting complex nested objects Prompt + schema Defines relationships between objects and arrays
Collecting information for critical decisions Either, with independent validation A schema doesn't verify factual correctness

You also don't need to choose between natural-language flexibility and structured output.

A practical workflow is to start with a prompt, inspect the results, and refine the instructions until the extracted information is useful.

Once you know which fields your application needs, define a schema for them. Keep the prompt for instructions that aren't naturally expressed through data types, such as selecting the correct price, interpreting experience ranges, or excluding unrelated page content.

This is where Spidra's support for both approaches is useful. You can experiment with extraction in the Playground and use the same prompt and schema through the API or SDK when you're ready to incorporate it into an application.

For larger collections, Spidra also supports batch scraping, which processes URLs individually and returns a separate result for each page.

From extraction to a recurring workflow #

Once your prompt and schema are settled, you can move the extraction into application code.

Spidra's Python SDK accepts the same extraction instructions and JSON Schema used in the Playground. Install the SDK:

pip install spidra

Save your schema as job-schema.json, then create the following script:

import json
import os
from pathlib import Path
from spidra import Spidra, ScrapeParams, ScrapeUrl

urls = [
    "https://www.python.org/jobs/8184/",
    "https://www.python.org/jobs/8181/",
    "https://www.python.org/jobs/8176/",
]

schema = json.loads(Path("job-schema.json").read_text())

prompt = (
    "Extract one main job posting from each URL into jobs. "
    "Return title, company, location, posted_date (YYYY-MM-DD), "
    "minimum_experience_years (the lower bound as a number), "
    "salary, telecommuting_allowed, and agencies_allowed. "
    "Preserve salary currency, range and period. "
    "Use null for missing information. Do not infer values "
    "or include related job listings."
)

client = Spidra(api_key=os.environ["SPIDRA_API_KEY"])

result = client.scrape(ScrapeParams(
    urls=[ScrapeUrl(url=url) for url in urls],
    prompt=prompt,
    schema=schema,
))

if result.ai_extraction_failed or result.extraction_empty:
    raise RuntimeError("Structured extraction did not complete")

Path("jobs.json").write_text(
    json.dumps(result.content, indent=2, ensure_ascii=False),
    encoding="utf-8",
)

The SDK submits the scrape and waits for the result, so you don't have to implement the API's job polling yourself.

The example stores the extracted JSON in a file. From there, you can apply the validation step above before sending records into a database, search index, or another part of your application.

For production use, handle scrape failures separately and check the resulting records against the rules your application requires. A successful extraction is the beginning of a reliable data workflow, not the entire validation process.

Choose the structure your application needs #

Prompt-based extraction is a good starting point when you need flexibility. Our three job postings show that a detailed prompt can return consistent JSON, including correctly typed fields and missing values.

Schema-based extraction becomes more valuable when you need a defined structure that downstream code can expect. It reduces the work of managing changing field names and data types, but it doesn't replace checks against the original source.

Start with a prompt to describe the information you need. Add a schema when the response becomes part of an application contract. Validate the values when accuracy matters.

With Spidra, you can try both approaches in the Playground, then reuse the extraction in your own application through the API or SDK.

── more in #structured-data 4 stories · sorted by recency
── more on @spidra 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
→ Live at https://your-agent.zahid.host ✓
Get free account → Pricing
from €0/mo · no card required
LIVE [news/prompt-based-vs-sche…] indexed:0 read:14min 2026-10-28 · —