<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title><![CDATA[Eduard Martin - Elasticsearch Labs]]></title>
    <description><![CDATA[Articles and tutorials from the Search team at Elastic]]></description>
    <copyright><![CDATA[© 2026. Elasticsearch B.V. All Rights Reserved]]></copyright>
    <image>
      <title><![CDATA[Eduard Martin - Elasticsearch Labs]]></title>
      <url>https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1121c0bf0e8a6e65/6a88da6340a1841030ef456f/search-labs-thumbnail.png</url>
      <link>https://www.elastic.co/search-labs/author/eduard-martin</link>
    </image>
    <link>https://www.elastic.co/search-labs/author/eduard-martin</link>
    <atom:link href="https://www.elastic.co/search-labs/rss/author/eduard-martin.xml" rel="self" type="application/rss+xml"/>
    <language><![CDATA[en]]></language>
    <lastBuildDate>Sat, 26 Sep 2026 05:44:33 GMT</lastBuildDate>
  <item>
    <title><![CDATA[Elasticsearch plugin for UBI: Analyze user data in Kibana]]></title>
    <description><![CDATA[Discover how to capture user behavior data using the Elasticsearch plugin for UBI and build a custom dashboard in Kibana to analyze it. ]]></description>
    <content:encoded><![CDATA[<p>In this article, we’ll show you how to capture and analyze user analytics data using the <strong>UBI</strong> <em>(User Behavior Insights)</em> standard in Elasticsearch.</p><p><em>You can learn more about UBI in </em><a href="https://www.elastic.co/search-labs/blog/elasticsearch-plugin-user-behavior-insights"><em>this article</em></a><em>.</em></p><p>Data collected with the UBI collector can be used on Kibana to build dashboards that open the window to users’ behavior in our application. In this blog, we will explore how to analyze UBI data in Kibana to gain insights into how our app is being used.</p><h2>Demo set up</h2><p>We can easily reproduce the demo in this blog following these steps:</p><p>1. Clone the repository</p>git clone https://github.com/Alex1795/ubi-dashboard-elasticsearch_blog.git 
cd ubi-dashboard-elasticsearch_blog<p>2. Install required libraries:</p>pip install -r requirements.txt<p>3. Run the setup script. Make sure to have the following environment variables set beforehand</p><ol><li><p>ES_HOST</p></li><li><p>API_KEY</p></li><li><p>KIBANA_HOST</p></li></ol>python setup.py<p>That’s all you need to do. If everything went well, you should see this output from the script execution:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0c568b39867bd357/6a170e3360084be8393c45ff/947a67ef7210fa76f62324a3eadb62a3e10bb887-1600x633.png" alt="" /><p>As we can see the script:</p><ul><li><p>Created two indices with the appropriate mappings</p></li><li><p>Indexed 23 documents to these indices</p></li><li><p>Uploaded some saved objects to Kibana</p></li></ul><p>Now, let’s take a look at what exactly this script did behind the scenes.</p><h2>Understanding the uploaded data</h2><p>First, we put some data in Elasticsearch before creating our visualizations.</p><p>You can reproduce the process manually in Kibana DevTools, copying the mappings and sample data and using the <strong>PUT &lt;index&gt;</strong> and <strong>PUT _bulk</strong> APIs, respectively.</p><h3>Ubi_events index</h3><p>User action data, documents are generated for every click (in this case), and it includes:</p><ul><li><p><strong>application</strong>: The client application that generated the event ("search-ui")</p></li><li><p><strong>action_name</strong>: Type of user action performed ("click")</p></li><li><p><strong>query_id</strong>: Links this event to the corresponding search query session</p></li><li><p><strong>client_id</strong>: A generated, unique ID that represents a user or session without revealing personal data. It is generated instead of using identifiable data like email addresses or usernames. This approach allows us to have privacy advantages such as safe analytics capabilities and secure data sharing without exposing PII, while still having important functionality like session continuity, behavioral analysis, or A/B testing.</p></li><li><p><strong>timestamp</strong>: ISO 8601 formatted timestamp when the event occurred</p></li><li><p><strong>message_type</strong>: Category of the event for processing ("CLICK_THROUGH")</p></li><li><p><strong>message</strong>: Human-readable description of what happened ("Clicked Fahrenheit 451")</p></li><li><p><strong>user_query</strong>: The original search term that led to this event ("fahrenheit")</p></li><li><p><strong>event_attributes</strong>: Nested object containing detailed event context:</p><ul><li><p><strong>object.device</strong>: Device type used by the user ("mobile")</p></li><li><p><strong>object.object_id</strong>: Unique identifier of the clicked item</p></li><li><p><strong>object.description</strong>: Details about the clicked item (book title, date, author)</p></li><li><p><strong>object.position.ordinal</strong>: Ranking position of the item in search results (1st)</p></li><li><p><strong>object.position.page_depth</strong>: Which page of results the item appeared on (1st page)</p></li><li><p><strong>object.user.ip</strong>: User's IP address</p></li><li><p><strong>object.user.city/region/country</strong>: Geographic location data</p></li><li><p><strong>object.user.location</strong>: Precise latitude/longitude coordinates</p></li></ul></li></ul><p>Sample document:</p>       {
         "application": "search-ui",
         "action_name": "click",
         "query_id": "2dd48446-7ca8-4510-89f4-2ebb67ed240b",
         "client_id": "8c1915fe-8ee0-4487-b801-3b1d67c25cf6",
         "timestamp": "2025-07-30T14:25:52.698Z",
         "message_type": "CLICK_THROUGH",
         "message": "Clicked Fahrenheit 451",
         "user_query": "fahrenheit",
         "event_attributes": {
           "object": {
             "device": "mobile",
             "object_id": "ZwoTM5gBPJ218VOaBpj4",
             "description": "Fahrenheit 451(1953-10-15) by Ray Bradbury",
             "position": {
               "ordinal": 1,
               "page_depth": 1
             },
             "user": {
               "ip": "192.168.1.100",
               "city": "New York",
               "region": "New York",
               "country": "United States",
               "location": {
                 "lat": 40.7128,
                 "lon": -74.006
               }
             }
           }
         }
       }<p>You can download the index mappings <a href="https://github.com/Alex1795/ubi-dashboard-elasticsearch_blog/blob/main/index_mappings/ubi_events-mappings.json">here</a></p><h3>Ubi_queries index</h3><p>Search data includes data relevant to each search executed by the users:</p><ul><li><p><strong>query_response_id</strong>: Unique identifier for this specific query response instance</p></li><li><p><strong>user_query</strong>: The original search term entered by the user ("fahrenheit")</p></li><li><p><strong>query_id</strong>: Unique identifier for the search query session</p></li><li><p><strong>query_response_object_ids</strong>: Array of object IDs that were returned as search results (["3", "9"])</p></li><li><p><strong>query</strong>: The complete Elasticsearch query object in JSON format, including search parameters, fields to search, result size, sorting, and metadata</p></li><li><p><strong>client_id</strong>: A generated unique ID that represents a user or session without revealing personal data. It is generated instead of using identifiable data like email addresses or usernames. This approach allows us to have privacy advantages such as safe analytics capabilities and secure data sharing without exposing PII, while still having important functionality like session continuity, behavioral analysis, or A/B testing.</p></li><li><p><strong>timestamp</strong>: Unix timestamp in milliseconds when the query was executed (1753885225098)</p></li></ul><p>Sample document:</p>    {
         "query_response_id": "03e8af3e-8725-49d9-99ad-36bf2a8e96d1",
         "user_query": "fahrenheit",
         "query_id": "f8b2f5bc-cb3c-49d4-86bc-19212a782ba7",
         "query_response_object_ids": [
           "3",
           "9"
         ],
         "query": """{"from":0,"size":20,"query":{"multi_match":{"query":"fahrenheit","fields":["author^1.0","name^1.0"]}},"_source":{"includes":["name","author","image_url","url","price","release_date"],"excludes":[]},"sort":[{"_score":{"order":"desc"}}],"ext":{"query_id":"f8b2f5bc-cb3c-49d4-86bc-19212a782ba7","user_query":"fahrenheit","client_id":"8c1915fe-8ee0-4487-b801-3b1d67c25cf6","object_id_field":null,"query_attributes":{}}}""",
         "client_id": "8c1915fe-8ee0-4487-b801-3b1d67c25cf6",
         "timestamp": 1753885225098
       }<p>You can download the index mappings <a href="https://github.com/Alex1795/ubi-dashboard-elasticsearch_blog/blob/main/index_mappings/ubi_queries-mappings.json">here</a><strong>.</strong></p><h3>Sample data</h3><p>We can use the <a href="https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-bulk">_bulk API</a> to index <a href="https://github.com/Alex1795/ubi-dashboard-elasticsearch_blog/blob/main/sample_documents/bulk_index.ndjson">some sample</a> data in both indices</p><p>This will create 6 documents in the <strong>ubi_queries </strong>index and 16 in the <strong>ubi_events</strong> index.</p><h3>Dashboard object</h3><p>Before going into details of the visualizations used in this example <a href="https://github.com/Alex1795/ubi-dashboard-elasticsearch_blog/blob/main/dashboards/web_analytics_dashboard.ndjson">here</a>, you can download the Saved Object of the full example dashboard and <a href="https://www.elastic.co/docs/explore-analyze/find-and-organize/saved-objects#saved-objects-import">import</a> it into your Kibana instance. This dashboard explores the most searched terms, when searches and events took place, and where they come from (in a map).</p><h2>Visualize Insights</h2><p>We are going to create a Kibana dashboard to analyze the most common metrics leveraging <a href="https://www.elastic.co/docs/explore-analyze/visualize/lens">Kibana Lens</a>. For a reference on available visualizations, visit <a href="https://www.elastic.co/docs/explore-analyze/visualize/supported-chart-types">this</a> page.</p><h3>Ubi_events</h3><p>We will start with some simple Metric visualizations created with Lens: <strong>Total events:</strong> Counts how many events were triggered in the timeframe. Uses a simple count of the documents in the index, denoted by <strong># Records</strong> in the field list.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt69d672ece8a13874/6a170e35286714284693e3be/2d06ff89f2cf43ee4102e9e01079ff63754e99fd-502x182.png" alt="" /><p><strong>Event actions: </strong>Counts actions by <code>action_name</code>. This is a simple count of documents split by <code>action_name.keyword</code>. In our sample data, we have two types of actions:</p><ul><li><p>click: Generated when a user clicks in the book link</p></li><li><p>search_input: Generated when a user enters text in the search box (debounce 300ms)</p></li></ul><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltda49e8d513f0166c/6a170e366f7f04c66c9148fb/3735206d066f62990159c0777243f8b3d0703b6b-1188x186.png" alt="" /><p>Now on table visualizations:</p><p><strong>Top clicks: </strong>A table with a count of the number of events split by the query they come from. It uses a Top values function on the <code>user_query.keyword</code>. This can give us visibility on which queries generate more interactions on our webpage.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt81925167886ba5e3/6a170e37b339d58be776a06c/87aba3bbb9cf32aefa2aa126ba8edfb6bb456ae4-223x296.png" alt="" /><p>Finally, some other visualizations:</p><p><strong>Device types:</strong> This visualization breaks down the percentage of events by the device they come from. The device can be one of three categories: Desktop, mobile, or tablet. This visualization is a pie that uses the top values of <code>event_attributes.object.device.keyword,</code> and can give us insights into which type of devices our users have. This can generate alerts if we detect an unexpected, sudden fall of events on a specific type of device, as this might indicate that a recent change in our app resulted in errors when accessing it from a device.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt695213931fbb528c/6a170e397d8d6741e770e7c2/b9e8d1a07fcebf73b3107bcbc728b77a5d30e6a6-846x484.png" alt="" /><p><strong>Events map:</strong> A <a href="https://www.elastic.co/docs/explore-analyze/visualize/maps/maps-getting-started">map visualization</a> that shows where the events are coming from, which allows us to see the geographical distribution of our users. Right now, this shows where individual documents come from, but this can also be used to see the density of users with a heatmap, for example.</p><p>This particular visualization can provide very interesting insights when used with different filters. For example, we can see where different search terms are coming from or where most of our clicks are originating. This can be useful information for making decisions on localization efforts or establishing differences across local markets. The map uses the location at <code>event_attributes.object.user.location</code>.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt1fbe510ac15fc06a/6a170e3b4a531b59a036a9fb/ca87fe7d5f84b9c38d9787c899c55bd48f2af9f5-1600x759.png" alt="" /><p><strong>UBI Events: </strong>A saved search with the latest UBI events documents</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt0101bc86e2a11639/6a170e3dd7c022575bde6545/73c94c7f0d238149851e066b4b53d16dff9e2e74-1309x379.png" alt="" /><h3>Ubi_queries</h3><p>Here we have visualizations from this index:</p><p><strong>Total queries:</strong> A simple document count of the index to show how many queries have been received in total. This shows the big picture and answers the question of how many total queries we had in the selected time window.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2f0e83ff0e87e104/6a170e3e286714171893e3c2/10af8288eaa278aff04625dab4d4a2c86c9ebf6d-218x90.png" alt="" /><p><strong>Unique clients: </strong>A <code>unique_count</code> of the field <code>client_id</code> to show how many different clients have used our website.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt30a15247e689a3c3/6a170e3f509168aec9e1bb82/baf7b29670f9392619dffef4800cb50efb3a0578-249x95.png" alt="" /><p><strong>Top queries (tag cloud):</strong> A Tag cloud of the top 5 most searched terms. This visualization uses the field <code>user_query.keyword</code> and allows us to easily see the main terms that our users are looking for.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt31218b03715ea15c/6a170e41e8fbce688139fd0b/833844afba1a5120ba2e83eade8f83954c34ba82-790x327.png" alt="" /><p><strong>Queries over time: </strong>A line chart of queries per hour, which uses a simple count metric in a horizontal axis of the field timestamp</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt3c0731a036283fad/6a170e42a6c2b9839ce79798/01d79d29cd63bbc3be273ed3f55f49cc01859f64-873x182.png" alt="" /><p><strong>Query terms over time:</strong> Similar to the last one, but broken down by the <code>user_query.keyword</code>. This chart can show how many different terms are searched over time.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltcb263c69b0e87ecb/6a170e4467045b7cac45c288/afb1c9c19919ca9117b5dc26c6f938c425261ae9-844x209.png" alt="" /><p><strong>Top queries:</strong> A Top values table showing how many times a term was searched. It uses the <code>user_query.keyword</code> field.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltfb8f5d3bf9cb7943/6a170e45a292995c17d010b6/19854feaa749b528e328e1e427aa285b2abd16b6-384x295.png" alt="" /><p><strong>Client queries:</strong> A Top values table of the <code>client_id</code> field that counts the total queries and unique queries per client.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt9201d14e53e3666a/6a170e4760084b756b3c4608/af18679364d92263913febf59c792957e41e5292-382x291.png" alt="" /><p><strong>No result queries:</strong> A Top value table that shows the top <code>query_terms</code> that didn’t match any document, and a Unique Count of the field client_id. This can be very useful to determine what products our website is lacking. For example, in an e-commerce book store, seeing regular searches for a particular book title could lead us to buy copies to sell. Alternatively, it can also indicate shortcomings in our search implementation, for example, if people are using question-based searches that align better with semantic search approaches.</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/bltc59e01f67e2899a1/6a170e48dc55de5d75e00e72/75dc6908767eb86ef2e2b8ac7e25c57b55f722ee-746x574.png" alt="" /><p>Here you can see the full dashboard:</p><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt4e197f27fb09906b/6a170e4a0e2e49c69541a1b3/39a00886ed753e12e8f2966b509b08afc45b4389-1600x913.png" alt="" /><img src="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt057ec5248cd60aca/6a170e4c8b73cb5b3b18a0ce/2eb980f0123d6464b94599bc01f61de542f8b8f9-1600x412.png" alt="" /><h2>Analysis of sample data</h2><p>In our dashboard, we can get some insights:</p><ul><li><p>Traffic is coming from 3 different cities in the US</p></li><li><p>Most of our users access our website from a desktop device, but we have a sizable number of users using a mobile device and even some using a tablet.</p></li><li><p>We can see the top query is “asimov,” but at the same time, we do not have any results. This might be a good indicator of what products should be prioritized for stock acquisition.</p></li></ul><p>To further this analysis, we could use Kibana’s Machine Learning capabilities to understand and predict behaviours on our website. Going even one step further, we can create alerts based on these behaviors using the different available connectors.</p><p>From a search relevance perspective, user behavior is a useful input for relevance engineering tools like <a href="https://www.elastic.co/search-labs/blog/elasticsearch-learning-to-rank-introduction">LTR</a>.</p><h2>Conclusion</h2><p>Data collected by the UBI collector can be easily used to have a better understanding of our users. The resulting dashboard becomes a live pulse of what our users are searching for and can point to data gaps to drive improvements in our search engine.</p><p><strong>Note:</strong> The o19s User Behavior Insights (UBI) plugin mentioned in this article is a third-party, community-maintained plugin and is not officially supported by Elastic. For questions or issues related to this plugin, please refer to the o19s UBI project repository at <a href="https://github.com/o19s/ubi">https://github.com/o19s/ubi</a>. </p>]]></content:encoded>
    <link>https://www.elastic.co/search-labs/blog/elasticsearch-plugin-user-behavior-data-kibana</link>
    <guid isPermaLink="true">https://www.elastic.co/search-labs/blog/elasticsearch-plugin-user-behavior-data-kibana</guid>
    <category><![CDATA[Basics]]></category>
    <dc:creator><![CDATA[Eduard Martin,Alexander Dávila]]></dc:creator>
    <enclosure url="https://static-www.elastic.co/v3/assets/bltefdd0b53724fa2ce/blt2d7e4a5bbd9427c2/6a170e4d0e2e4905b641a1b7/04f1738a38cead88c9a67b0f863171b4b43010ab-1600x913.png" length="0" type="image/png"/>
    <pubDate>Fri, 26 Sep 2025 00:00:00 GMT</pubDate>
  </item>
  </channel>
</rss>