--- title: How cards compute user visits slug: '3195' canonical_url: https://docs.coveo.com/en/3195/ collection: coveo-analytics source_format: adoc --- # How cards compute user visits When reporting on [visits](https://docs.coveo.com/en/271/), you may notice some [discrepancies between the visit counts](#total-unique-visit-computation) depending on the type of [report cards](https://docs.coveo.com/en/267/) you're using. That's because the database operations carried out to create [visit metric and visit metric time series](#visit-metric-and-visit-metric-time-series-cards) differ from those carried out on [other cards](#other-cards). The visit metric and visit metric time series cards rely on _union_ operations, whereas the other cards rely on _join_ operations. This article provides more details on those differences. For details on the different types of cards that Coveo offers, see [Report cards](https://docs.coveo.com/en/1972/). ## Visit metric and visit metric time series cards [Visit metric](https://docs.coveo.com/en/1972#visit-metric) and [Visit metric time series](https://docs.coveo.com/en/1972#visit-metric-time-series) cards display visits which are extracted from a table built by taking the union of tables containing the following types of events: * [Searches](https://docs.coveo.com/en/2949#search-performsearch) * [Clicks](https://docs.coveo.com/en/2949#click-documentview) * [Custom events](https://docs.coveo.com/en/2949#custom-customevent) The union is made without regards to relationships between event types, meaning that it ignores the sequence of events during the visits. To see what it looks like in action, see the [Filtering - union of events](#filtering-union-of-events) example. ### Filters in visit metric and visit metric time series cards A filter in visit metric and visit metric time series cards is based on occurrences of the filter criteria within the visits. **Example** If you define a filter on case creation, it will return all visits having at least one case creation event. If you create a visit metric card about visits with clicks, and apply the filter on it, it will return the number of visits having at least one click and at least one case created regardless of whether the case creation was related to the click or the search. In summary, a visit could contain a case created without having any related searches and clicks. If a visit has at least one click, it's counted as part of the visits with clicks. ![Add a Visit Card panel showing filter options | Coveo Platform](https://docs.coveo.com/en/assets/images/coveo-analytics/filters-showing-visits.png) > **Note** > > [Global dimension filters](https://docs.coveo.com/en/1675/) defined on the report (if any) are added to the **Show visits containing** filter using the `AND` operator. > > ![Add a Visit Metric card panel showing filter combination example | Coveo Platform](:https://docs.coveo.com/en/assets/images/coveo-analytics/filters-in-visit-metric-card.png) > > In this case, the card will count the number of unique visits in which a customer opened a support case while they were in Canada. ## Other cards Other cards (that is, not visit metric and visit metric time series) display visits which are extracted from a table built by taking the joined result of the `searches`, `clicks`, and `custom_events` tables. The relationships between the resulting visit events are as follows: * [Searches](https://docs.coveo.com/en/2949#search-performsearch) ** Search has 0 to N clicks ** Search has 0 to N custom events * [Clicks](https://docs.coveo.com/en/2949#click-documentview) ** Click has 1 and only 1 search * [Custom events](https://docs.coveo.com/en/2949#custom-customevent) ** Custom event has 0 to 1 search Since custom events could exist without an associated search, the visit count includes the visits from the search events and the custom events. Unless a specific filter on clicks is applied, if the **Unique Visit** metric is used, the `clicks` table isn't joined at all. Since the visit information can be determined via searches only in the case of clicks, a click is always related to a search unlike custom events. > **Note** > > In other cards (that is, not visit metric and visit metric time series), you can join custom events with the last Search ID (default) or the last Visit ID. > > To see what it looks like in action, see the [last search ID](#filtering-join-between-events-custom-events-on-last-search-id) and the [last visit ID](#filtering-join-between-events-custom-events-on-last-visit-id) examples. ### Filters in other cards A filter in other cards (that is, not visit metric and visit metric time series) joins the different tables (that is, `searches`, `clicks`, and `custom_events`) related to each event type required by the card. The relationship between the tables enforces the following database operations (i,e., joins) between them: * _Searches left outer join Clicks_ resulting in all searches including those having no clicks. A left outer join on clicks is done so there are no standalone clicks. Therefore, the search is enough to consider visits. * _Searches full outer join custom events_ resulting in all searches and all custom events including: ** Searches having no custom events ** Custom events having no related searches The filter applied to the resulting table is defined by the required relationship. The dimensions and metrics used in the card define the combined tables used. **Example** Taking the previous [example](#example), using a filter on a case creation, a metric card counting unique visits with clicks will result in a different count. ![Add a Metric card panel showing filters and metrics for unique visits with clicks and case submitted | Coveo Platform](https://docs.coveo.com/en/assets/images/coveo-analytics/add-a-metric-card-panel-for-unique-visits.png) The condition applied on the resulting table will filter out all the custom events related to a case creation having no associated searches and clicks. The resulting table will only include visits where a search and a click lead to a case creation, meaning it will likely have a lower number of visits than when using the visit metric or visit metric time series card. ## Total unique visit computation When adding a visit metric or a visit metric time series card, versus another type of card, based on the number of unique visits, it's possible to see a small difference between the two counts since both types of cards compute visits differently. ### Visit exclusion/inclusion based on date time The behavior of the visit metric and visit metric time series cards is primarily based on the [Visit Browser](https://docs.coveo.com/en/274/) behavior. The **Visit Browser** excludes visits that started in the 24 hours prior to the specified time range. This ensures the visits appearing in the **Visit Browser** are complete. The **Visit Browser** doesn't return visits missing half of their events since they started before the specified time range. Since other cards include all the events for the specified time range, they will include visits discarded by the visit metric and visit metric time series cards. The **Visit Browser** also includes visit events occurring up to 24 hours past the defined time range end. The goal of the **Visit Browser** is to show all the events related to the visits. This behavior can cause some numbers to differ from those on other cards. **Example** Say a visit started within the specified time range, and a click occurred just after. The event is included in the visit for the visit metric and visit metric time series cards. See the [Date time exclusion - join between events](#date-time-exclusion-join-between-events) example. Other cards would exclude that visit, see the [Date time exclusion - union of events](#date-time-exclusion-union-of-events) example. ### Visit expiration Lastly, visits expire after 30 minutes of inactivity. To learn respectively how visit metric, visit metric time series cards, and other cards handle visit expiration, see the [Expired visit - union of events](#expired-visit-union-of-events) and the [Expired visit - join between events](#expired-visit-join-between-events) examples. ### Date time exclusion - union of events In the following database example, there's one unique visit on January 16th, 2020. [%header,cols="~,~,~,~,~"] |=== |Row |Date time |Event type |Search ID |Visit ID |1 |January 15, 2020 23:50:00 |search |1 |1 |2 |January 16, 2020 0:02:00 |search |2 |1 |3 |January 16, 2020 0:05:00 |click |2 |1 |4 |January 16, 2020 8:35:00 |custom | |2 |=== where: * On row `1`, the visit started on Jan. 15th, and is therefore discarded. * Row `4` is the only valid row. ### Date time exclusion - join between events In the following database excerpt, there are two unique visits on January 16th, 2020. [%header,cols="10*"] |=== 4+|Search event 3+|Click event 3+|Custom event |Row |Date time |Search ID |Visit ID |Date time |Search ID |Visit ID |Date time |Search ID |Visit ID |1 |January 15, 2020 23:50:00 |1 |1 | | | | | | |2 |January 16, 2020 0:02:00 |2 |1 |January 16, 2020 0:05:00 |2 |1 | | | |3 | | | | | | |January 16, 2020 8:35:00 |null |2 |=== where: * On row `1`, The visit started on January 15th, and is therefore discarded. * Row `2` and `3` are valid. ### Expired visit - union of events In the following database excerpt, there are three unique visits. [%header,cols="~,~,~,~,~"] |=== |Row |Date time |Event type |Search ID |Visit ID |1 |January 16, 2020 0:02:00 |search |1 |1 |2 |January 16, 2020 0:05:00 |click |1 |1 |3 |January 16, 2020 1:02:00 |search |2 |2 |4 |January 16, 2020 2:05:00 |click |2 |3 |=== where the click event on row `4` occurred over one hour after the search, hence why a new visit ID is generated. ### Expired visit - join between events In the following database excerpt, there are two unique visits. [%header,cols="7*"] |=== 4+|Search event 3+|Click event |Row |Date time |Search ID |Visit ID |Date time |Search ID |Visit ID |1 |January 16, 2020 0:02:00 |1 |1 |January 16, 2020 0:05:00 |1 |1 |2 |January 16, 2020 1:02:00 |2 |2 |January 16, 2020 2:05:00 |2 |3 |=== > **Note** > > The visit count is based on the Search ID dimension to prevent the count from changing while adding or removing dimensions to the card since the join is dynamic and based on the used dimensions. ### Filtering - union of events In the following database excerpt, there are three unique visits containing a click and a case creation. [%header,cols="~,~,~,~,~,~"] |=== |Row |Date time |Event type |Search ID |Visit ID |Event type |1 |January 16, 2020 0:02:00 |search |1 |1 |search |2 |January 16, 2020 0:05:00 |click |1 |1 |click |3 |January 16, 2020 0:06:00 |custom |1 |1 |case creation |4 |January 16, 2020 0:05:00 |search |2 |2 |search |5 |January 16, 2020 0:06:00 |click |2 |2 |click |6 |January 16, 2020 0:07:00 |custom | |2 |case creation |7 |January 16, 2020 0:07:00 |search |3 |3 |search |8 |January 16, 2020 0:08:00 |click |3 |3 |click |9 |January 16, 2020 0:09:00 |search |4 |3 |search |10 |January 16, 2020 0:10:00 |custom |4 |3 |case creation |=== ### Filtering - join between events (custom events on last search ID) In the following database excerpt, there's one unique visit with a click and a case creation. [%header,cols="11*"] |=== 4+|Search event 3+|Click event 4+|Custom event |Row |Date time |Search ID |Visit ID |Date time |Search ID |Visit ID |Date time |Last Search ID |Visit ID |Event type |1 |January 16, 2020 0:02:00 |1 |1 |January 16, 2020 0:05:00 |1 |1 |January 16, 2020 0:06:00 |1 |1 |case creation |2 |January 16, 2020 0:05:00 |2 |2 |January 16, 2020 0:06:00 |2 |2 | | | | |3 | | | | | | |January 16, 2020 0:07:00 | |2 |case creation |4 |January 16, 2020 0:07:00 |3 |3 |January 16, 2020 0:08:00 |3 |3 | | | | |5 |January 16, 2020 0:09:00 |4 |3 | | | |January 16, 2020 0:10:00 |4 |3 |case creation |=== where only row `1` is valid. ### Filtering - join between events (custom events on last visit ID) In the following database excerpt, there are three unique visits with a click and a case creation. [%header,cols="11*"] |=== 4+|Search event 3+|Click event 4+|Custom event |Row |Date time |Search ID |Visit ID |Date time |Search ID |Visit ID |Date time |Last Search ID |Visit ID |Event type |1 |January 16, 2020 0:02:00 |1 |1 |January 16, 2020 0:05:00 |1 |1 |January 16, 2020 0:06:00 |1 |1 |case creation |2 |January 16, 2020 0:05:00 |2 |2 |January 16, 2020 0:06:00 |2 |2 |January 16, 2020 0:07:00 | |2 |case creation |3 |January 16, 2020 0:07:00 |3 |3 |January 16, 2020 0:08:00 |3 |3 |January 16, 2020 0:10:00 |4 |3 |case creation |4 |January 16, 2020 0:09:00 |4 |3 | | | |January 16, 2020 0:10:00 |4 |3 |case creation |=== where rows `1`, `2`, and `3` are valid. > **Note** > > When joining custom events on visit IDs, other cards tend to behave like visit metric and visit metric time series cards.