Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,45 +7,43 @@ on:
- 'v*'
pull_request: {}

env:
PNPM_VERSION: 6.19.0

jobs:
lint:
name: Linting
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.0.1
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v2
version: 8
- uses: actions/setup-node@v4
with:
node-version: 16.x
node-version: 20
cache: pnpm
- run: pnpm install
- run: pnpm run lint

test:
name: Testing
timeout-minutes: 60
runs-on: ubuntu-latest
# Playwright 1.36 installs system packages that only exist up to Ubuntu 22.04.
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v3
- uses: pnpm/action-setup@v2.0.1
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v3
version: 8
- uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
cache: pnpm
- name: Install dependencies
run: pnpm install
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
- name: Run Playwright tests
run: pnpm exec playwright test
- uses: actions/upload-artifact@v3
- uses: actions/upload-artifact@v4
if: always()
with:
name: playwright-report
Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,18 @@ on:
branches:
- main

env:
PNPM_VERSION: 6.19.0

jobs:
upload:
name: Building and Uploading
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.0.1
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v2
version: 8
- uses: actions/setup-node@v4
with:
node-version: 16.x
node-version: 20
cache: pnpm
- run: pnpm install
- run: pnpm build
Expand Down
13 changes: 5 additions & 8 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,18 @@ on:
tags:
- '*'

env:
PNPM_VERSION: 6.19.0

jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: pnpm/action-setup@v2.0.1
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
- uses: actions/setup-node@v2
version: 8
- uses: actions/setup-node@v4
with:
node-version: 16.x
node-version: 20
cache: pnpm
- run: pnpm install
- run: npm publish
Expand Down
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
## v1.2.0 (unreleased)





#### :rocket: Enhancement
* [#12](https://github.com/TelemetryDeck/WebSDK/issues/12) Send a `TelemetryDeck.Web.linkClick` signal when an outbound link is clicked, with the destination as `TelemetryDeck.Link.*` parameters. Any element can be tracked explicitly with `data-td-link`, excluded with `data-td-ignore`; automatic tracking can be turned off with `data-outbound-links="false"`.
* Send a `TelemetryDeck.Web.pageLeave` signal when a page is hidden or unloaded, carrying scroll depth and engaged time as `TelemetryDeck.PageEngagement.*` parameters. On by default, opt out with `data-page-engagement="false"`.

## v1.0.5 (2022-05-27)

Expand Down
128 changes: 127 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,138 @@ Note that if you are a programmer working on a node package based JavaScript app
Once you have your App ID, edit the source code of your website and add the following code snippet to the `<head>` section of every page, making sure to replace `<YOUR APP ID>` with your actual App ID:

```html
<script async
<script
async
src="https://cdn.telemetrydeck.com/websdk/telemetrydeck.min.js"
data-app-id="<YOUR APP ID>"
></script>
```

## Signals

The SDK sends a `pageview` when a page loads, a `TelemetryDeck.Web.pageLeave` signal when it is left, and a `TelemetryDeck.Web.linkClick` signal for every click on an outbound link.

### `pageview`

Sent as soon as the script loads. Contains the page `url`, the `referrer`, the browser `locale` and the SDK version.

### `TelemetryDeck.Web.pageLeave`

Sent once per page load, the first time the page is hidden or unloaded (tab switched, tab closed, navigation to another page). It reports how far visitors scrolled and how long the page was actually visible:

| Parameter | Value |
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `TelemetryDeck.PageEngagement.scrollDepth` | Deepest point of the page that was in view, in percent (`0`–`100`). A page that fits the viewport counts as `100`. |
| `TelemetryDeck.PageEngagement.scrollDepthMilestone` | The highest milestone reached: `"0"`, `"25"`, `"50"`, `"75"` or `"100"`. Handy as a dimension for donut charts and funnels. |
| `TelemetryDeck.PageEngagement.engagedSeconds` | Seconds the page was visible in the foreground, rounded to whole seconds. |

The signal carries the same `url` and `referrer` as the `pageview`, so both can be joined per page.

Page engagement tracking is on by default. To turn it off, add `data-page-engagement="false"` to the script tag:

```html
<script
async
src="https://cdn.telemetrydeck.com/websdk/telemetrydeck.min.js"
data-app-id="<YOUR APP ID>"
data-page-engagement="false"
></script>
```

#### Example: average scroll depth per page

```json
{
"queryType": "groupBy",
"granularity": "all",
"filter": {
"type": "selector",
"dimension": "type",
"value": "TelemetryDeck.Web.pageLeave"
},
"dimensions": [{ "type": "default", "dimension": "url", "outputName": "URL" }],
"aggregations": [
{
"type": "doubleMean",
"name": "Average Scroll Depth",
"fieldName": "TelemetryDeck.PageEngagement.scrollDepth"
}
]
}
```

### `TelemetryDeck.Web.linkClick`

Sent whenever a visitor clicks a link that leads to another site (a different host than the current page, over `http` or `https`). Same-site links, `mailto:` and `tel:` links are not tracked. The signal is sent with `navigator.sendBeacon`, so it never delays the navigation, and it works for links that are added to the page after it has loaded.

| Parameter | Value |
| ------------------------------- | --------------------------------------------------------------------------------------------------- |
| `TelemetryDeck.Link.url` | The absolute destination URL. Credentials in the URL are removed; query and fragment are kept. |
| `TelemetryDeck.Link.host` | The destination host name, e.g. `example.com`. Handy for a "top outbound sites" chart. |
| `TelemetryDeck.Link.isOutbound` | `"true"` when the destination is on another site, `"false"` for explicitly tracked same-site links. |

The signal carries the same `url` and `referrer` as the `pageview`, so you can see which pages send visitors where.

#### Tracking buttons and chosen links

Add `data-td-link` to any element to track clicks on it, whether or not it is an outbound link. On a link the attribute can be left empty; on a button or any other element, set it to the destination:

```html
<a href="/pricing" data-td-link>Pricing</a>

<button
data-td-link="https://buy.example.com/checkout"
onclick="location.href = 'https://buy.example.com/checkout'"
>
Buy now
</button>
```

Add `data-td-ignore` to a link, or to any of its ancestors, to never track it:

```html
<a href="https://example.com" data-td-ignore>Not tracked</a>

<nav data-td-ignore>
<a href="https://mastodon.social/@example">Not tracked either</a>
</nav>
```

#### Tracking only chosen links

To track only the links you marked with `data-td-link` and no other outbound links, add `data-outbound-links="false"` to the script tag:

```html
<script
async
src="https://cdn.telemetrydeck.com/websdk/telemetrydeck.min.js"
data-app-id="<YOUR APP ID>"
data-outbound-links="false"
></script>
```

#### Example: most clicked outbound sites

```json
{
"queryType": "topN",
"granularity": "all",
"filter": {
"type": "selector",
"dimension": "type",
"value": "TelemetryDeck.Web.linkClick"
},
"dimension": { "type": "default", "dimension": "TelemetryDeck.Link.host", "outputName": "Site" },
"metric": { "type": "numeric", "metric": "Clicks" },
"threshold": 10,
"aggregations": [{ "type": "longSum", "name": "Clicks", "fieldName": "count" }]
}
```

## Testing locally

Signals sent from `localhost`, `127.0.0.1` or `file:` URLs are marked as test mode automatically. You can force test mode with `data-is-test-mode="true"` and point the SDK at a different ingest server with `data-api`.

## 📱 You need an App ID

Every application and website registered to TelemetryDeck has its own unique ID that we use to assign incoming signals to the correct app. To get started, create a new app in the TelemetryDeck UI and copy its ID.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@telemetrydeck/web",
"version": "1.1.0",
"version": "1.2.0",
"description": "Send analytics signals to TelemetryDeck",
"main": "dist/telemetrydeck.js",
"module": "dist/telemetrydeck.mjs",
Expand Down
22 changes: 22 additions & 0 deletions src/config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// Read once at load time: `document.currentScript` is only available while the
// script element is executing, so this module must be evaluated first.
const script = document.currentScript;
const dataset = script ? script.dataset : {};
const { location = {} } = globalThis;

export const appId = dataset.appId;
export const api = dataset.api ?? 'https://nom.telemetrydeck.com/v2/w/';

// Page engagement (scroll depth, engaged time) is on by default; opt out with
// `data-page-engagement="false"`.
export const pageEngagement = dataset.pageEngagement !== 'false';

// Automatic tracking of clicks on outbound links is on by default; opt out
// with `data-outbound-links="false"`. Elements marked `data-td-link` are
// tracked either way.
export const outboundLinks = dataset.outboundLinks !== 'false';

export const isTestMode =
dataset.isTestMode === 'true' ||
/^localhost$|^127(\.\d+){0,2}\.\d+$|^\[::1?]$/.test(location.hostname) ||
'file:' === location.protocol;
Loading
Loading