Understanding the Solr JSON Response
When you query your Opensolr Web Crawler index via the /select API, you get back a JSON object. This page explains every section of that response so you know exactly how to parse it in your application.
The Basic Response Structure
Here is a simplified example of what comes back when you search:
{ "responseHeader": { "status": 0, "QTime": 12 }, "response": { "numFound": 1542, "start": 0, "numFoundExact": true, "docs": [ { ... }, { ... } ] }, "highlighting": { "doc_id_1": { ... }, "doc_id_2": { ... } }, "facet_counts": { "facet_fields": { ... } }, "spellcheck": { "suggestions": [ ... ], "collations": [ ... ] } }
responseHeader
"responseHeader": { "status": 0, "QTime": 12 }
| Field | Description |
|---|---|
status |
0 means success. Any other value means an error occurred. |
QTime |
Query execution time in milliseconds. This is how long Solr took to process your query (not including network time). A good search returns in under 50ms. |
response
This is the main section containing your search results.
"response": { "numFound": 1542, "start": 0, "numFoundExact": true, "docs": [ ... ] }
| Field | Description |
|---|---|
numFound |
Total number of documents matching your query. This is the number you display as "Showing results 1-10 of 1,542". |
start |
The offset you requested (from the start parameter). |
numFoundExact |
Whether numFound is exact (true) or an approximation. Almost always true. |
docs |
Array of document objects — your actual search results. |
A Document Object
Each item in the docs array looks like this:
{ "id": "bc434cee9e50b48f80095c9f49bdeae3", "uri": "https://yoursite.com/blog/my-article", "title": "My Article Title", "description": "A short description of the article...", "text": "The full body text of the page...", "og_image": "https://yoursite.com/images/article-thumb.jpg", "meta_icon": "https://yoursite.com/favicon.ico", "meta_domain": "yoursite.com", "meta_detected_language": "en", "content_type": "text/html", "creation_date": "2026-02-20T14:30:00Z", "timestamp": 1771684200, "sent_pos": 0.153, "sent_neu": 0.752, "sent_neg": 0.095, "sent_com": 0.9856, "score": 1.8234, "price_f": 29.99, "currency_s": "USD" }
The fields you get back depend on what you specified in the fl (field list) parameter. The score field is special — it is computed at query time and represents the relevancy score for that document.
Tip: Only request the fields you actually need. Requesting
text(full body text) for every result increases response size significantly. If you only display titles and snippets, usefl=id,uri,title,description,og_image,score.
highlighting
If you set hl=true in your query, you get a highlighting section keyed by document ID:
"highlighting": { "bc434cee9e50b48f80095c9f49bdeae3": { "title": ["My <em>Article</em> Title"], "description": ["A short description about <em>article</em> writing..."], "text": ["...the main body discusses <em>article</em> formatting and..."] }, "another_doc_id": { "title": ["Another <em>Article</em>"] } }
How to use it in your code:
- Loop through your
docsarray - For each doc, look up
highlighting[doc.id] - If a highlighted version exists for a field, use it instead of the raw field value
- The
<em>tags wrap the matching search terms — style them with CSS (bold, background color, etc.)
// Example: get the best title to display var docId = doc.id; var hl = data.highlighting[docId] || {}; var displayTitle = (hl.title && hl.title[0]) ? hl.title[0] : doc.title;
Important: Highlighted text contains HTML (
<em>tags), so you should insert it usinginnerHTML, nottextContent. The rest of the text is already HTML-escaped by Solr.
facet_counts
If you set facet=true, you get a facet_counts section:
"facet_counts": { "facet_fields": { "meta_detected_language": [ "en", 834, "de", 245, "fr", 123, "es", 89, "nl", 42 ], "currency_s": [ "USD", 156, "EUR", 89 ] } }
The facet arrays alternate between value and count: ["en", 834, "de", 245, ...] means 834 results in English, 245 in German, etc.
Parsing facets in JavaScript:
var langFacets = data.facet_counts.facet_fields.meta_detected_language; var facets = []; for (var i = 0; i < langFacets.length; i += 2) { facets.push({ value: langFacets[i], count: langFacets[i+1] }); } // facets = [{value: "en", count: 834}, {value: "de", count: 245}, ...]
You can then render these as clickable filter buttons or a sidebar. When the user clicks "English (834)", add fq=meta_detected_language:en to your query to filter.
spellcheck
If you enabled spellcheck, you get suggestions for misspelled words:
"spellcheck": { "suggestions": [ "opnesolr", { "numFound": 1, "suggestion": ["opensolr"] } ], "collations": [ "collation", "opensolr search" ] }
The collations section is the most useful — it gives you a corrected version of the entire query that you can show as "Did you mean: opensolr search?".
Parsing collations:
var collations = data.spellcheck ? data.spellcheck.collations : []; if (collations.length >= 2) { var suggestion = collations[1]; // The corrected query string // Display: "Did you mean: <a>suggestion</a>?" }
Error Responses
If something goes wrong, the response looks like this:
{ "responseHeader": { "status": 400 }, "error": { "msg": "undefined field: nonexistent_field", "code": 400 } }
Always check responseHeader.status — if it is not 0, read the error.msg for details. Common errors:
- 400 — Bad query syntax, undefined field, or invalid parameter value
- 500 — Server error (rare, usually a misconfigured query)
stats
If you requested stats on a numeric field (e.g., stats=true&stats.field=price_f):
"stats": { "stats_fields": { "price_f": { "min": 4.99, "max": 299.99, "count": 156, "missing": 1386, "sum": 12450.50, "mean": 79.81 } } }
This is useful for displaying price ranges or other numeric summaries in your UI.
Paste any website URL into the RAG in 60 Seconds sandbox. The Web Crawler fetches your pages, Opensolr generates the vector embeddings, and you get keyword + vector hybrid search plus a RAG answer on your own content — live, on a temporary index, with the keyword-only, vector-only and hybrid results shown side by side. No account, no OpenAI key, nothing to install.
Try AI Hybrid Search in 60 seconds →