# Site Search If a site includes a search function of any kind (ex.: product search in a webshop), visitors expect to be able to search for things in the language of the website -- to input any term into the search fields and receive appropriate results immediately. **A pretty standard example** Let's say that a visitor uses the search field of `www.example.com` to search for the word "**product**". Upon pressing enter, they are navigated to `https://www.example.com/search?q=product`. The server will detect and use the value of the `q` parameter and runs whatever server-side search mechanism it uses to search for this term, assemble a list of results and construct a result page to send to the browser. Because the server is the one, who does the actual searching, we call this approach _server-side search_. **This introduces a potential issue** On a proxied site, however, we run up against a problem: the original server does not know about the translations. Requests are automatically relayed to the original server. If a visitor were to type "**produkt**" on the German domain (resulting in an URL navigation to `https://de.example.com/search?q=produkt`), that is the same as relaying a search query with German language content to the original site. Not possessing a _German language index_, the response is certain to contain 0 results. The fact that the proxy is CMS-agnostic and that it generally doesn't require that translated content be shared with the original server also means that this same content will not be available to the indexing/search software that is running on the original. Luckily, the server-side approach isn't the only option, when it comes to having some search functionality on a website! **Recommended solution** The fact, that proxied pages themselves are _publicly available for indexing by search engine bots_ comes in handy. A search engine that supports site-specific queries can provide localized search via __client-side__ AJAX requests. There are two aspects to this kind of solution that you should consider: On the one hand, such a site search has to be coded in JavaScript in the form of an override (an example with a detailed explanation follows below), and depending on how ornate/feature-laden the original's search functionality is, complexity of the override implementation can vary from the relatively simple to the astonishingly complex. On the other hand, familiarity with the various indexing-related conditions of your chosen vendor is also important (we provide pointers to some documentation for Bing, since it is the vendor used in the example). In our experience, it is not at all unusual for search engines to act leisurely in their pace. Remember that a site can only be indexed after it is published over the proxy. On the same note, the [publishing method](../../dashboard2/index.html#publish) you use can also have a bearing on the way search & indexing will work, so a case-by-case analysis is a must. Note that the Client-Side Translation publishing method is *not compatible* with a site search integration of the type described here. ### Third-party Integrations #### Bing Bing's Web Search API can be used for site search integration purposes over the proxy. In order to access Bing's API, you will need to purchase an API key. See the details on [Microsoft Azure](https://azure.microsoft.com/en-us/try/cognitive-services/?api=bing-web-search-api) on procuring one, and see the [pricing page](https://azure.microsoft.com/en-us/pricing/details/cognitive-services/search-api/web/) for a detailed description of the various service tiers. Consult the [Webmaster Tools Documentation](https://www.bing.com/webmaster/help/help-center-661b2d18) concerning general usage-related matters. You can submit a domain for indexing in Bing [here](https://www.bing.com/toolbox/submit-site-url). Submission of specific URLs is possible [here](https://www.bing.com/webmaster/help/submit-urls-to-bing-62f2860a), but this feature is limited to root domains at the time of writing: until such time as this limitation is lifted, you might only be able to use this targeted indexing feature with subdirectory publishing. ##### Bing: Verification of subdomains If you want to track the indexing of your subdomains in Webmaster Tools and do SEO tracking, you'll need to verify ownership of the target language subdomains. The available methods are [described here](https://www.bing.com/webmaster/help/how-to-verify-ownership-of-your-site-afcfefc6). The XML-based approach is the simplest to implement over the proxy (it can be done without having to apply any changes on the origin): create a temporary [Page Content Override](../../dashboard2/pagemodifiers/contentoverride.html) with the contents of `BingSiteAuth.xml` (content type should be `text/xml`). This exposes the authorization XML over the proxy domains. From then on, you are free to add the target language subdomains in Webmaster Tools and verify them one-by-one. ## Part II: Example In the rest of this documentation page, let us detail how a simple site search integration could be implemented as injected JavaScript over the proxy using [v7 of the Microsoft Web Search API](https://docs.microsoft.com/hu-hu/rest/api/cognitiveservices/bing-web-api-v7-reference). ### Page Modifiers Customized JavaScript can be injected into the `
` tag of each page over the proxy. This capability is the entryway for a search override. To add injected JavaScript you'll find an editor in Page Modifiers > Javascript editor, where you can type or copy & paste Javascript code. After saving the modifier, it will show up in the page source over the proxy after a refresh (but note that cache settings might get in the way of an instantaneous update on the live domain!). Site search functionality is frequently displayed to the visitor in the form of an input field and a button. We'll go with this familiar scenario and use the following minimal webpage for this tutorial: ``` htmlResult summary
").text(result.snippet)) }; ``` Among the available options for creating DOM elements (`document.createElement`, string contatenation, etc.), the jQuery-based approach is clear and concise. Many bells and whistles can be added to a DOM handler, such as a pager, for example, which would require that we handle offsets (only hinted at by `createRequest` in this tutorial) and add Previous/Next buttons, etc. Our tutorial, however, does not extend to those details and we conclude it here. ### Notes Some frequent, but non-essential complexity of client-side search is omitted from our example: - offsets (a Bing-specific term) are only alluded to. Any search API will support requests for the next batch of search results for the same search query. This is usually exposed to the end user in the form of a pager that, when clicked, sends the same request but increments the `offset` by 10. Such a feature causes both `renderResult` to manage the concept of a pager and `sendRequest`/`createRequest` to have to keep tabs on tne current `offset`. - a search field is also generally available on all pages on a site, not just the search results page. This means that an integration needs to ensure that the user is redirected to the search results page and that query parameters are appropriately handled. Besides using the values of the input field (a user-driven query after page load), a search integration usually has to be able to extract `produkt` from `https://de.example.com/search?q=produkt` to start a default search on the search results page when it loads for the first time. This is usually not difficult, but as we've said previously, much depends on specific circumstance. - a search integration also has to be prepared to display a "No results." search result page if the search engine returns no hits. Such natural language has to exposed in a way that can be translated using the proxy. ### Code We repeat the code from the discussion above in its entirety. In summary, when injected into the example webpage, it will override both the search field and the button to request search results from Bing via an AJAX call and then displays those search results in-place. ``` javascript (function (){ "use strict"; var config = { API_KEY: "nmtcxylkj56lkjmnnj3mg782nmvf23gz", // example only! API_URL: "https://api.cognitive.microsoft.com/bing/v7.0/search", DOMAIN: location.host }; $(document).ready(overrideSearch); // OVERRIDE function overrideSearch () { $("#form").on("keydown", overrideInput); $("#button").on("click", overrideInput); }; function overrideInput () { if (event.keyCode === 13) { event.preventDefault(); sendRequest($("#input").val(), renderResult); } }; function overrideClick(){ event.preventDefault(); sendRequest(this.previousSibling.value, renderResult); }; // REQUEST function sendRequest (term, callback) { $.ajax(createRequest(term)).success(function (resp) { callback(resp); }) }; function createRequest (term, offset) { return { beforeSend: function (xhr) { xhr.setRequestHeader("Ocp-Apim-Subscription-Key", config.API_KEY); }, error: function (xhr, error, thrown) { console.log("Error during request!"); }, url: config.API_URL, type: "get", data: { q: "site:" + config.DOMAIN + "/ " + term, count: 10, offset: offset || 1 } }; }; // DOM function renderResult(response) { $("#results").show().empty(); if (typeof response.webPages.value !== "undefined") { for (var hit in response.webPages.value) $("#results").append(createResultItem(response.webPages.value[hit])) } }; function createResultItem (result) { return $("
").text(result.snippet)) }; })(); ```