> For the complete documentation index, see [llms.txt](https://docs.jentis.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.jentis.com/use-cases-and-tutorials/activate-tags-once-per-page-session-or-user/creating-a-custom-variable-for-scope.md).

# Creating a Custom Variable for Scope

To get started, we need to create a custom variable. In the JENTIS State and JENTIS Data Layer context, a variable is a storage unit that contains specific data or information about the user, session, or other elements.

This variable will define either "true" or "false" as the value, with the following meaning:

* "**true**": this is the first occurrence per this variable's scope (page/session/user scope is defined in the variable, see the following section)
* "**false**": this is **not** the first occurrence per this variable's scope

With this design, we can use that as a condition in a trigger that reads "activate once per ... equals: true" (or false), respectively. This gives you a readable JENTIS configuration that helps with maintenance.

We need the variable that holds most of the logic to achieve this result.

In JENTIS, navigate to your list of variables and create a new one. There, select the server-side (backend) custom JavaScript variable. Name it "Once per User" and enter the following code:

{% code overflow="wrap" lineNumbers="true" %}

```javascript
async function() {
  const STORAGE_KEY_NAME  = "recurrence_limiter";
  const RECCURNC_LIMITER  = this.getFrontendVariable("user_doc_id");
  const MAX_STORAGE_SIZE  = 3;
  
  let existing_ids  = await this.toolInstanceStorage.read(STORAGE_KEY_NAME) || "";

  if(existing_ids && RECCURNC_LIMITER != null && RECCURNC_LIMITER != "" && existing_ids.indexOf(RECCURNC_LIMITER) >= 0){
    return false; //this value was received previously
  } else if(RECCURNC_LIMITER && RECCURNC_LIMITER != null && RECCURNC_LIMITER != "") {
    existing_ids += RECCURNC_LIMITER+";";

    if(existing_ids.split(";").length > MAX_STORAGE_SIZE+1){
      existing_ids = existing_ids.split(";");
      existing_ids.shift();
      existing_ids = existing_ids.join(";");
    }

    this.toolInstanceStorage.write(STORAGE_KEY_NAME, existing_ids, Date.now()+94608000000);

    return true; //this value is new
  }
  return null;
}
```

{% endcode %}

Let's run through this code line by line.

We must define the scope first to return either true (this observation is new in respect of the scope) or false (this observation is not new).

This is done so in the "**RECCURNC\_LIMITER**" constant. It is assigned the value of a variable in reference, in this example it is "user\_doc\_id" (the ID of the JENTIS User ID variable, the single unique value for a user in JENTIS Tag Manager).

With this set, we have determined the scope. We will return the value "true" only once per this single user ID.

Further, the constant "MAX\_STORAGE\_SIZE" determines how many inputs of an ID should be persisted. For a user, this can not be more than one value. However, for other scopes ("once" per transaction ID, session ID, page ID, etc.), it can be a good idea to also keep track of the recent values (the storage here works in a first-in-first-out scheme; if the max. count is reached, the first value inserted will be removed from the memory).

The value of "**STORAGE\_KEY\_NAME**" is a static string that defines the key name for the persistence of the ID. The name can be anything (but should be used only in this use case to mitigate a situation of collision).

No other value in the code must be customized. The most crucial section is the RECCURNC\_LIMITER value, so let's discuss this in more detail.

## Storage Collision

Remember, all storage read and write operations happen in JENTIS in the context of a given account, tool, and user by design. It is not possible for a value, which you store in such variables, stored on the server side, to be exchanged or confused between users or tools. So if this same server-side variable code is executed on a different user (website visitor) or tool (once for "GA4" and once for "Facebook CAPI" the result will be per each tool once per user "true", so one tool is not affecting the others).

### Determining Scopes via Variables <a href="#activatetagsonceperpagesessionoruser-determiningscopesviavariables" id="activatetagsonceperpagesessionoruser-determiningscopesviavariables"></a>

In the example above, we used the user ID (user\_doc\_id variable) to make this variable return true only once for a given user ID. This was done in reference to `this.getFrontendVariable("user_doc_id")` (Find the backend function reference here: [Functions and Interface References](/developer-guide/functions-transformations.md)) which will read the variable ID "user\_doc\_id" that is the user's ID with JENTIS.

Now, we can adjust this to read any ID (a session ID, transaction ID, or page ID). As long as this ID is persisted, the variable "Once per ..." will return only once "true" and for all further observations of the same value, a "false."x

So, for example, if we want to track something once per page, this would be a good starting point. Let's create a page ID that remains constant for the scope of a website. If the site is reloaded, the ID should be made anew. But as long as the user doesn't navigate, the value remains consistent. This is especially interesting for single-page applications when multiple similar events happen but with no particular order (ie, a race condition) and you want a tag to execute just once per page.

We must create a new variable, so please navigate again to the JENTIS Tag Manager: Variables section and create a new custom JavaScript variable (frontend, client-side).

The name "Once per page random value" might be a good idea. Use the following code in this variable:

{% code overflow="wrap" lineNumbers="true" %}

```javascript
function() {
    window["jentis_once_per_page_randomvalue"] = window["jentis_once_per_page_randomvalue"] || Math.round(2147483647 * Math.random());

    return window["jentis_once_per_page_randomvalue"];
}
```

{% endcode %}

This creates a static variable (initially a random integer value) on your global scope (window). Please remember that you may want fewer objects ("pollution") on your global scope. In that case, you'd need to adjust the code accordingly to put this random value in a better position in accordance with your page guidelines.

This variable persists the value for a given page's lifecycle (page load to unload on navigation to the following webpage). This value is reported to JENTIS to indicate a website's uniqueness.

Now update your "Once per page" variable (just renamed for this use case, but the same code as the "Once per user" variable) to read the value of your newly created frontend variable "once\_per\_page\_random\_value" (the ID of your new variable) instead of the "user\_doc\_id."

With all this ready, let's head to the configuration to combine all puzzle pieces.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.jentis.com/use-cases-and-tutorials/activate-tags-once-per-page-session-or-user/creating-a-custom-variable-for-scope.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

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.
