Search results

Displaying search results on your website is probably the most basic search functionality you need to provide to your website visitors. Without this basic functionality, search just does not offer any value for your visitors (unless you can manage with autosearch only, which is possible in some cases, but should be used with caution).

This guide helps you on your way with retrieving Pandosearch API data and converting this into a search results page. While this guide can be read independently, it can be helpful to read the live suggestions first for some additional context.


Generally speaking, the following technical steps are needed to show search results on your website:

  • Ensure you have a search form pointing to a search results path
  • Get the search query from an incoming HTTP request on your website
  • Retrieve search result data from Pandosearch using the Search API action
  • Convert retrieved search result data into HTML to display to visitors

Some points of note before we go to the example implementation:

  • Other than for the live suggestions implementation in the previous guide, you do not specifically need JavaScript (or another client-side language compiling to JavaScript) to make this happen. Any programming language will do as long as it has reasonable support for building websites and web applications.
  • As there are many web-friendly programming languages and frameworks nowadays, this guide provides pseudo-code only to illustrate the basic concepts.
  • We focus on server-side Pandosearch API interaction and HTML rendering, as this is the scenario we most commonly see in practice. A client-side implementation, however, is certainly possible and generally follows the same process.

Example implementation

Following up on the live suggestions example, we will be building a search results page for our demo collection. When following along in your programming language of choice, just replace with your own Pandosearch collection name to display your own search results instead.

Search form

The search results page is the path the search form on the website points to using the action attribute value. A very basic example search form may look like this:

<form action="/search">
  <input type="text" name="q" id="search-input" autocomplete="off" placeholder="Type a search query...">
  <input type="submit" value="Search">

Forms use the HTTP GET method by default. On submitting the form using the "Search" button, the search query is therefore appended to the action path as a query parameter. The parameter name is usually q, but anything will do.

When searching for "pandosearch" using the example form above, the full path sent to the web server will look like this:


Send API request

With the search form in place, you will need to catch the /search path somewhere in your server-side web application code. When doing this, you specifically need to parse the q query parameter value, as this is the value to send to the Pandosearch API later on.

Depending on the language and web framework used, you may need to manually unescape any special characters in the search query.

With a clean q value and your Pandosearch collection, you have all the information you need to construct a full Pandosearch API URL for the Search action. For and search query pandosearch, the URL looks like this:

Use your favourite HTTP client library to send a GET request to this URL.

Parse API response

The above Pandosearch API request will return raw JSON data containing search results for the given q value.

As can be seen in the Search API documentation, this possibly contains a lot of information. For this example implementation, the relevant parts are total, hits and pagination.

With these three values, you can display an HTML page containing:

  • The total number of search results found for the given query.
  • The hits found (URLs pointing to web pages or other available content). The first 10 hits are returned by default.
  • A pagination interface for navigating to the next/previous page or a specific page number

On processing the API response data, you need to convert the raw JSON data into a data structure native to the programming language used. Most programming languages have highly optimized JSON parsing libraries available to do this for you.

Convert to HTML

With parsed API data in place, it is up to you to convert this into HTML output suitable for use on your website. As this widely varies in practice depending on the web framework and styling approach used, it does not really make sense for us to provide a full example here.

Instead, we'll provide a basic HTML template. To enable some if and for logic, we use EEx-inspired templating code with variables and expressions in <% %> brackets.

First the full template code (surrounding HTML such as header, navigation and footer omitted):

<h1>Search results for '<%= q %>' (<%= total %>)</h1>

<%= for hit <- hits do %>
    <h2><a href="<%= hit.url %>"><%= hit.fields.title %></a></h2>
    <p><%= hit.fields.body %></p>
<% end %>

  <%= if pagination.current > 1 do %>
    <a href="<%= pagination.prelink %>&amp;page=<%= current - 1 %>">Previous</a>
  <% end %>

  <%= if pagination.current < pagination.numPages do %>
    <a href="<%= pagination.prelink %>&amp;page=<%= current + 1 %>">Next</a>
  <% end %>

For syntax simplicity, we access nested API data values using dot notation (e.g. hit.fields.title). This should look familiar to people working with e.g. JavaScript objects.

Let's walk through the example part by part. First, the page title:

<h1>Search results for '<%= q %>' (<%= total %>)</h1>

Given 12 results for query "pandosearch", this would display "Search results for 'pandosearch' (12)".

As a baseline, it is usually a good idea to display the search query and the total number of search results. Both help visitors to quickly validate where they are and what to expect in terms of data volume.

The HTML here is a very basic example, the visual appearance is entirely up to you.

Time to move on to the actual search results:

<%= for hit <- hits do %>
    <h2><a href="<%= hit.url %>"><%= hit.fields.title %></a></h2>
    <p><%= hit.fields.body %></p>
<% end %>

This is a simple for loop through all the hits returned by Pandosearch. A couple of things to consider:

  • Make sure to clearly show a link pointing to the url value. The title value is usually OK, but making the whole container (a <div> in the example above) clickable can be helpful too.
  • The title and body fields are used here, as they are present in almost every Pandosearch implementation. We support HTML-based highlighting to indicate the search term's presence. As body content can be quite lengthy, by default only a short snippet is shown containing the search term (highlighted if desired).
  • Depending on your configuration, many other fields can be returned in the API response data. Examples are thumbnail image URLs, a page type (news, faq, product), a slug (Home / Guides / Search results) and many, many more.
  • In addition to the above, API response data may also contain facets. This allows for further filtering within the current result set. This can be very powerful in terms of helping your visitors, but is also very customer-specific in terms of which facets are present and how they should be displayed.

Fields and facets are highly configurable and differ between implementations. Handling all possible variations is therefore beyond the scope of this guide.

Our implementation process always includes conversations on the exact fields and facets needed. In these conversations, we also address how fields and facets should be displayed in search result pages.

With hits handled, let's get back to our example HTML template. The only part left is pagination:

  <%= if pagination.current > 1 do %>
    <a href="<%= pagination.prelink %>&amp;page=<%= current - 1 %>">Previous</a>
  <% end %>

  <%= if pagination.current < pagination.numPages do %>
    <a href="<%= pagination.prelink %>&amp;page=<%= current + 1 %>">Next</a>
  <% end %>

The main parts explained:

  • The <nav> container is a simple wrapper element to indicate that this is navigational content.
  • The if statements ensure "Previous" and "Next" links are only shown when there actually is a previous and/or next page.
  • The pagination.prelink template variable contains a prepopulated query string containing all current request parameters. You only need to append the page= query string parameter.

As you can see, the pagination API response data provides you with all the information needed to implement the logic needed for creating a pagination user interface.

In addition to the above, in real-world pagination interfaces, some extra features are sometimes included:

  • Hide the page navigation container if there is only one page in total.
  • Show "First" and "Last" links to directly navigate to the first and last batch of results.
  • Show direct links to specific pages, usually with the page number itself as link text ("1", "2", "3", etc.)

Another approach could be to implement an "infinite scroll" interface. At the bottom of the page, a "Show next 10 results" link can be displayed, which triggers a search call to the next page. This does involve some client-side logic to do a partial page update.

All of these approaches have their specific pros and cons, which is beyond the scope of this guide.


This brings us to the end of the example implementation. Starting with a search form, we've constructed an API request using submitted form data, processed the response data, and finally converted this into HTML output to display to visitors.

Real-world usage

The example implementation given above is meant to serve as a starting point. This means we intentionally left out lots of additional features and edge cases.

Some specific options have been mentioned explicitly. In addition to that, there are some more generic things to consider when building a real-world search results page:

  • Server-side or client-side – while a server-side approach gives you more control and flexibility, the downside is an extra roundtrip to your server before the Pandosearch API is called. This may be necessary due to security policies, and it may also be a functional choice to do this. For completeness, we do want to point out that calling our search API directly from client-side JavaScript is perfectly fine for us in terms of cross-domain HTTP requests. Also, as a search results page typically does not need to be indexed by Google, Bing and other search engines, client-side HTML rendering should not be a problem in terms of search engine optimization (SEO).
  • Search request options – while out of scope for the example implementation, there are a number of additional request parameters beyond just q. This may help you in creating the exact user experience you want. See the API documentation for further details.
  • URL encoding – As website visitors are free to enter anything in your search box, be sure to correctly URL encode the search query and all other request data you send to Pandosearch.
  • Error handling – As with all APIs, be sure to gracefully handle errors. While we do our best to always return valid results, our servers may return HTTP 5xx errors in unfortunate events. Also, other errors like internet hickups will simply happen from time to time. Be sure to cover the most common error cases, otherwise you run the risk of severely hurting your visitors' experience.
  • Additional response data – we deliberaty focused on basic response data in our example implementation. In addition to that, both facets (for result filtering) and suggestions (for "Did you mean?" support) data can be of value when building a search results page. Read the Response section in the Search API documentation for full details.
  • HTML escaping – in our basic example templates, we did not address the issue of HTML escaping. Our search API data may contain HTML tags, such as <b></b> for highlighting the search term in a text snippet (markup is configurable). We also make sure we encode extended characters, like for instance ™, as valid HTML (&trade;), so you don't have to replace or escape anything.