> For the complete documentation index, see [llms.txt](https://docs.fact-finder.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fact-finder.com/webcomponents-overview/web-components-4.x./guides/advanced/login-tracking.md).

# Login Tracking

Configure secure login tracking before your first FactFinder search.

This page discusses the **requirements** and **challenges** that need to be considered for a successful integration of login tracking with Web Components. It also explores some options for the configuration.

The key parameter in login tracking is the shop visitor's ***user ID*** managed by your **shop system**. When you configure Web Components with this *user ID*, it will be added to subsequent requests (e.g. *search* or *recommendations*) to FactFinder, which produces more **personalized results**.

{% hint style="info" %}
It is good practice to anonymize the user ID for data protection.
{% endhint %}

### Requirements

* Your page must detect whether the user is logged in or not.
* User ID must be passed to Web Components.
* Login data must be cleared from the browser when the user logs out.

### Challenges

* The login tracking request must happen before the first search request (`search-immediate`).
* Rendering the user ID directly into HTML is to be avoided for security reasons.
* Keeping the login status of server and client in sync.

### The building blocks

Some required parts depend on whether you configure Web Components through the `ff-communication` element or through JavaScript.

The following parts are required in **both** scenarios:

* `factfinder.communication.sessionManager.setLoginData(userId)`
  * Sets the `userId` on Web Components and `localStorage`, so it will be included in subsequent requests. On page load, Web Components will automatically try to read the `userId` from `localStorage`.
* `factfinder.communication.sessionManager.clearLoginData()`
  * Clears the `userId` from Web Components and `localStorage`.
* `factfinder.communication.sessionManager.clearAllSessionData()`
  * Clears login data and additionally the *session ID*.
* `factfinder.communication.Tracking.loginWithConfig()`
  * Sends a *login* tracking request with the current Web Components configuration.

If you use `ff-communication`, you additionally need:

* `ffCommunicationReady` event

Integrations *without* `ff-communication` use:

* `ffReady` event
* `factfinder.communication.EventAggregator.addFFEvent(event)`

Lastly, your *shop server* has to keep track of the user's login status and pass the information to the client. Typically, this happens through:

* Browser cookies

or

* Client-side AJAX requests

{% hint style="info" %}
We recommend the use of **cookies** because they are sooner available to the client than the results of AJAX requests. This enables you to send the initial search request earlier and reduces waiting times for the shop visitor.
{% endhint %}

### The Challenges

**Login tracking**, setting the *user ID* in particular, and `search-immediate` are two competing concepts.

If you use `ff-communication`'s `search-immediate` attribute, the first search request will be sent as soon as `ff-communication` finishes initializing. The *user ID*, however, must be set before the first request happens in order to include the `userId` parameter in the request.

Using the `search-immediate` attribute thus leaves no choice other than rendering the *user ID* directly into the `user-id` HTML attribute of `ff-communication`. However, this is usually not acceptable as the HTML output, along with the *user ID*, may get cached and served to other clients.

This makes the `search-immediate` attribute **unsuitable** to combine with login tracking. It is best to send the initial search request **manually** after configuring the *user ID*.

Apart from setting the *user ID*, you also have to **unset** it again. Web Components stores the *user ID* in the browser's `localStorage` so it remains available after navigating to another page and can be included in requests. When the user logs out, the *user ID* shall no longer be included and the session shall be reset.

There are four things your **shop system** should communicate to each page with Web Components:

* User is logged in
  * To allow *user ID* to be included in requests.
* User has just logged in
  * To signal that a login tracking request shall be sent.
* User is logged out
  * To clear the *user ID* and no longer send it with requests.
* User has just logged out
  * To clear the *session ID* and allow for a new session to start.

### Integration

This section shows a schematic example of how you can integrate login tracking with cookies for communicating from the shop system to the client.

Whether you use `ff-communication` or a JavaScript-based approach to configure your application, the fundamental flow of information remains the same.

The cookie names in this example are suggestions. They are not reserved names by the Web Components library. You can choose whatever names you find suitable.

### Configuration with `ff-communication`

This listing represents a server-side HTML template.

```html
<script>
    // This event is emitted when `ff-communication` finished initializing.
    document.addEventListener(`ffCommunicationReady`, ({ factfinder, searchImmediate }) => {

        const getCookie = key => document.cookie
                .split(`; `)
                .find(kv => kv.startsWith(`${key}=`))
                ?.split(`=`)[1];

        const userId = getCookie(`shop_userId`);

        // If `userId` is present, the user is logged in.
        if (userId) {
            // Setting `userId` everytime is not strictly necessary but has no bad side effect either.
            // It ensures correct application state.
            factfinder.communication.sessionManager.setLoginData(userId);

            // This cookie must only be sent once after the user logged in.
            // It is used here to send the tracking request.
            const hasJustLoggedIn = getCookie(`shop_hasJustLoggedIn`);

            if (hasJustLoggedIn) {
                factfinder.communication.Tracking.loginWithConfig();
            }
        } else {
            // This cookie must only be sent once after the user logged out.
            const hasJustLoggedOut = getCookie(`shop_hasJustLoggedOut`);

            if (hasJustLoggedOut) {
                // Caution! `clearAllSessionData` clears the session ID which starts a new FactFinder Analytics session.
                // Avoid calling it on each page because non-logged-in sessions shall persist.
                factfinder.communication.sessionManager.clearAllSessionData();
            } else {
                // Calling `clearLoginData` even if user is logged out to ensure clean application state.
                factfinder.communication.sessionManager.clearLoginData();
            }
        }

        // Server-side HTML templating. The syntax is likely to be different in your environment.
        // Call `searchImmediate` only on appropriate pages.
        // This `searchImmediate` is the same that `ff-communication` would call.
    <% if (searchImmediate) { %>
        searchImmediate();
    <% } %>

    });
</script>

<body>
    <ff-communication
          url="..."
          channel="..."
          version="..."
          api="..."
          ...
    ></ff-communication>
</body>
```

### Configuration with JavaScript

If you don't use `ff-communication`, the `ffCommunicationReady` event is not available. Instead, you use `ffReady`.

This listing only shows the differences to the `ff-communication` approach:

* Configuration of Web Components
* Initiating the initial search

```html
<script>
    document.addEventListener(`ffReady`, ({ factfinder }) => {
        // Configure Web Components with JavaScript through:
        // - factfinder.communication.globalSearchParameter
        // - factfinder.communication.globalCommunicationParameter


        // Session managing and tracking related code like in previous listing.
        // ...
        // ...


    <% if (searchImmediate) { %>
        factfinder.communication.EventAggregator.addFFEvent({
            type: `search`,
            query: `*`,
            searchImmediate: true,
        });
    <% } %>

    });
</script>
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.fact-finder.com/webcomponents-overview/web-components-4.x./guides/advanced/login-tracking.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
