> For the complete documentation index, see [llms.txt](https://docs.graspil.com/en/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.graspil.com/en/app/website-script.md).

# Website script

## What is it?

The website script is a small piece of JS code you install on your website (landing page, online store, blog — anything). It lets you:

1. **Automatically pass a visitor's UTM tags into the bot.** If a user arrives on your site from an ad with `utm_source`, `utm_medium`, etc., and later starts your bot from that same site, all those tags get attached to them in Graspil — so you see the full path from ad click to bot conversation.
2. **Detect the user's geolocation** (by IP, before they even start the bot).
3. **Pass any custom parameters** you want to attach to the user — a CRM ID, a Google Analytics/Yandex Metrika `client_id`, the ID of a product they viewed, etc.
4. **Authorize the user in the bot without codes or SMS** — the script passes visitor data through a unique token that arrives in the bot's `start` parameter when the bot is launched.

{% hint style="info" %}
The install snippet with your key lives in your dashboard: [Website extension](https://app.graspil.com/code4-site)
{% endhint %}

## How it works

1. You install the code on your site (see below).
2. Every visitor gets a unique token. All collected data is attached to that token: UTM tags, geolocation, your custom fields.
3. The script finds bot links on the page (`https://t.me/your_bot` or `tg://resolve?domain=your_bot`) and automatically inserts this token into the `start` parameter (or `startapp` for Mini App links).
4. When the user clicks such a link and starts the bot, Graspil sees the token in the `start` parameter and loads all the data previously collected for that visitor.

{% hint style="warning" %}
The script only finds and processes **links to a bot whose username matches the bot connected in your Graspil account** (see [My bots](https://app.graspil.com/bots)). If the bot name in the link doesn't match, the link won't be processed. If your links aren't working, check the bot name under "My bots" → "Edit".
{% endhint %}

## Installation

Add the code below anywhere on the page (ideally in `<head>` or at the top of `<body>`, before any bot links):

```html
<script>
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({key:i});
  var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src="https://s.graspil.com?l="+l;
  f.parentNode.insertBefore(j,f);})(window,document,"script","graspil","YOUR_KEY");
</script>
```

You can copy your key from the dashboard, on the [Website extension](https://app.graspil.com/code4-site) page — the code there already has your key filled in.

Nothing else is required — in basic mode the script automatically finds bot links on the page and inserts the token.

## Which bot links are processed automatically

| Link type                          | Example                                       | Where the token goes |
| ---------------------------------- | --------------------------------------------- | -------------------- |
| Regular bot link                   | `https://t.me/graspil_bot`                    | `?start=token`       |
| Mini App link (path-based)         | `https://t.me/graspil_bot/app`                | `?startapp=token`    |
| Deep link (opens the Telegram app) | `tg://resolve?domain=graspil_bot`             | `&start=token`       |
| Deep link to a Mini App            | `tg://resolve?domain=graspil_bot&appname=app` | `&startapp=token`    |

{% hint style="warning" %}
The `start` (or `startapp`) value in the link will be replaced by the token. If a bot link already had other parameters (e.g. `?ref=abc`), they will be removed and replaced by the token. If that's a problem for your bot, contact support.
{% endhint %}

{% hint style="info" %}
The script only looks for `https://t.me/...` and `tg://resolve...` links. Links like `http://t.me/...` (without `https`) or `https://telegram.me/...` are not recognized.
{% endhint %}

## What does the bot do with this token?

The token the script inserts into `start` is the same `start` parameter Telegram passes to your bot on launch. For more on how the `start` parameter is structured and processed in Graspil, see [Processing start parameters (UTM)](/en/app/start-utm.md).

If you need to fetch the data attached to a token (UTM tags, geolocation, your custom fields) directly through the API, use [Getting data by start token](/en/api/get-data-by-start-token.md).

## Configuring the script

By default the script only needs the `key`. You can pass additional settings alongside it:

```html
<script>
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({key:i, autoBot: false, initialDelay: 500});
  var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src="https://s.graspil.com?l="+l;
  f.parentNode.insertBefore(j,f);})(window,document,"script","graspil","YOUR_KEY");
</script>
```

<table><thead><tr><th width="180">Option</th><th width="150">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>key</code></td><td>string</td><td>Required. Your key from the dashboard.</td></tr><tr><td><code>autoBot</code></td><td>boolean</td><td>Default <code>true</code>. Set to <code>false</code> to disable automatic scanning and rewriting of bot links. In that case, call <code>window.graspil.submit()</code> manually (see below). Useful if you want full control over when the token gets applied.</td></tr><tr><td><code>initialDelay</code></td><td>number (ms)</td><td>Default <code>1000</code>. How many milliseconds after the script loads before the first automatic link check runs.</td></tr><tr><td><code>fields</code></td><td>object</td><td>Custom fields to attach to the user right away, e.g. <code>fields: {crm_id: '12345'}</code>. Equivalent to calling <code>addField()</code> for each field (see below).</td></tr><tr><td><code>yandex_client_id</code></td><td>boolean or string</td><td>Set to <code>true</code> to have the script collect the Yandex Metrika ClientID (from the <code>_ym_uid</code> cookie or via <code>ym()</code>) and send it as the <code>yandex_client_id</code> field. Pass a string to store it under a custom field name instead.</td></tr><tr><td><code>google_client_id</code></td><td>boolean or string</td><td>Same, but for Google Analytics (ClientID from the <code>_ga</code> cookie).</td></tr><tr><td><code>yandex_counter</code> / <code>ym_id</code></td><td>number/string</td><td>Your Yandex Metrika counter ID. Needed if the <code>_ym_uid</code> cookie isn't set yet when the page loads — the script will then request the ClientID via <code>ym(counterId, 'getClientID', ...)</code>.</td></tr></tbody></table>

## Renaming the global variable (if `window.graspil` is already taken)

By default the script works through the global variable `window.graspil` — that's where your config is pushed (`w[l]=w[l]||[]`, with `l` set to `"graspil"` in the snippet), and it's the same object that later exposes `addField`/`submit`/`getChannelLink`.

If your site already has its own script using the name `graspil` (a naming conflict — rare, but it happens), you can change this name. It's controlled by the fourth argument in the snippet itself:

```html
<script>
  (function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({key:i});
  var f=d.getElementsByTagName(s)[0],j=d.createElement(s);j.async=true;j.src="https://s.graspil.com?l="+l;
  f.parentNode.insertBefore(j,f);})(window,document,"script","myQueueName","YOUR_KEY");
</script>
```

Here `"graspil"` was replaced with `"myQueueName"` (pick any name that isn't already used on your page). After that, all config and every method live under `window.myQueueName` instead of `window.graspil` — so use `window.myQueueName.addField(...)`, `window.myQueueName.submit(...)`, and `window.myQueueName.getChannelLink(...)` instead.

{% hint style="warning" %}
Only rename it if you have an actual conflict. In the vast majority of cases you don't need to change anything — leave it as `"graspil"`.
{% endhint %}

{% hint style="info" %}
If you're editing the snippet by hand, don't remove the `?l="+l` part of the `j.src` line. That's how the script learns which name you chose. Without it, the script keeps using `window.graspil` even if you changed the fourth argument.
{% endhint %}

## Manual control (JS API)

Once the script has loaded, `window.graspil` exposes a few methods you can call at any time from your own page JS.

### `window.graspil.addField(name, value)`

Adds a custom field that will be attached to the visitor the next time data is sent to the server (during automatic processing or when calling `submit()`).

```js
window.graspil.addField('crm_id', '12345')
window.graspil.addField('product_viewed', 'sku-9981')
```

{% hint style="info" %}
Fields added via `addField` only live for the current page load — add them again on each new page (or pass them via `fields` in the config if they don't change).
{% endhint %}

### `window.graspil.submit(applyToLinks, callback)`

Manually triggers a bot-link scan and token application, regardless of `autoBot`. Useful when:

* you've disabled automatic mode (`autoBot: false`) and want to control exactly when the token is applied;
* bot links appear on the page dynamically (e.g. after a button click) and you want them processed right away instead of waiting for the automatic check;
* you need the token itself in your JS code, not just applied to a link (see example below).

| Argument       | Type     | Default | Description                                                                                       |
| -------------- | -------- | ------- | ------------------------------------------------------------------------------------------------- |
| `applyToLinks` | boolean  | `true`  | If `false`, the token is **not** written into links on the page — you only get it via `callback`. |
| `callback`     | function | `null`  | Called with an object like `{ 'https://t.me/bot?...': 'token' }` — one entry per bot link found.  |

**Example: just read the token without touching links on the page**

```js
window.graspil.submit(false, function (tokensByLink) {
    // tokensByLink = { 'https://t.me/graspil_bot': 'bai38kal' }
    for (const link in tokensByLink) {
        console.log('Token for', link, '=', tokensByLink[link])
    }
})
```

**Example: manually process a link added to the page after a click**

```js
document.getElementById('show-bot-link').addEventListener('click', function () {
    // ...you just added a new <a href="https://t.me/graspil_bot"> to the DOM
    window.graspil.submit() // finds the new link and applies the token
})
```

### `window.graspil.getChannelLink(channelName)`

Builds a channel/bot link through the `tlin.cc` shortener, automatically appending all data collected on the site (UTM tags and your custom fields). Returns a `Promise` that resolves to the link string.

```js
window.graspil.getChannelLink('mychannel').then(function (link) {
    // link = 'https://tlin.cc/mychannel?source=google&medium=cpc'
    document.getElementById('channel-link').href = link
})
```

For more on redirect links themselves, see [Landings (tlin.cc redirect)](/en/app/landings.md).

## Getting the token without writing JS

If you don't need to code anything and just want bot links on your site to automatically get a token — you don't need to do anything, the script does this in basic mode (`autoBot: true`, enabled by default). The token appears in the `href` attribute of the bot link — you can check it via browser DevTools (F12 → Elements → find the link).

## Technical details and limitations

* The script stores issued tokens in the browser's `sessionStorage` — a new tab or a closed browser means a new token will be requested. Tokens are not shared across tabs.
* The script never writes cookies. It only **reads** the `_ym_uid` (Yandex Metrika) and `_ga` (Google Analytics) cookies, and only if the corresponding settings are enabled.
* Only regular `<a href="...">` links present in the DOM are found. Links generated in non-standard ways (e.g. only via `onclick`) or living inside a Shadow DOM aren't detected automatically — call `window.graspil.submit()` manually after they appear.
* If the script is temporarily unavailable or a network error occurs, your site keeps working as normal — the error is only logged to the browser console and doesn't affect the rest of the page.
* On single-page sites (SPA), the script automatically tracks URL changes (via `pushState`/`replaceState`) and re-checks links on the new "page" — no extra setup needed.

## FAQ

<details>

<summary>Bot links on my site aren't changing, the token isn't applied — what's wrong?</summary>

The most common cause is that the bot name in the link doesn't match the bot connected to your Graspil account. Check the bot name under [My bots](https://app.graspil.com/bots) → select the bot → "Edit", and compare it with what's in the link (`https://t.me/BOT_NAME`).

Also make sure:

* the script is installed on the page and loads without errors (check the Network tab in DevTools);
* the bot link starts with exactly `https://t.me/` or `tg://resolve` — other variants (`http://`, `telegram.me`) aren't supported.

</details>

<details>

<summary>Can I use the script together with my own parameters in the bot link (e.g. ?ref=abc)?</summary>

No — when applying the token, the script removes any other parameters from the link and leaves only `start`/`startapp` with the token value. Pass any data you need (including your `ref`) through `window.graspil.addField()` instead — it will be attached to the same token and available through the get-data-by-token API.

</details>

<details>

<summary>How do I turn off automatic token insertion into links?</summary>

Add `autoBot: false` to the config when initializing the script (see "Configuring the script" above) and call `window.graspil.submit()` manually whenever you need it.

</details>

<details>

<summary>Does the script work with multiple bots on the same site?</summary>

Yes, the script processes every bot link found on the page that matches a bot connected to your account, no matter how many there are.

</details>
