@kharon-labs/browser 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +98 -2
- package/dist/index.cjs +653 -0
- package/dist/index.d.ts +271 -0
- package/dist/index.js +630 -0
- package/dist/tracker.cjs +228 -0
- package/dist/tracker.d.ts +130 -0
- package/dist/tracker.js +205 -0
- package/dist/v1.js +1 -0
- package/package.json +27 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kharon Labs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,99 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @kharon-labs/browser
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Personalize parts of any website with Kharon Labs. Mark the regions you want to personalize, keep
|
|
4
|
+
your own copy as the defaults, and the package swaps in the variant Kharon picks for each visitor,
|
|
5
|
+
then measures it against a holdout.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @kharon-labs/browser
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
On a site without a bundler, use the script-tag build at `https://kharonlabs.com/sdk/v1.js`. On a
|
|
12
|
+
React site (including Next.js and React Native Web), use
|
|
13
|
+
[`@kharon-labs/react`](https://www.npmjs.com/package/@kharon-labs/react), which is built on this package.
|
|
14
|
+
|
|
15
|
+
## Plain HTML
|
|
16
|
+
|
|
17
|
+
```html
|
|
18
|
+
<head>
|
|
19
|
+
<!-- Optional: hides slots (never the page) until the swap, for at most 500 ms. -->
|
|
20
|
+
<style id="kharon-af">[data-ge-slot]{visibility:hidden!important}</style>
|
|
21
|
+
<script>window.__kharonAf=Date.now();setTimeout(function(){var s=document.getElementById("kharon-af");s&&s.parentNode.removeChild(s)},500)</script>
|
|
22
|
+
<script src="https://kharonlabs.com/sdk/v1.js" data-key="ge_pk_…" async></script>
|
|
23
|
+
</head>
|
|
24
|
+
<body>
|
|
25
|
+
<section data-ge-slot="hero">
|
|
26
|
+
<h1 data-ge-field="headline">Grow faster</h1>
|
|
27
|
+
<a data-ge-field="ctaLabel" data-ge-attr="href:ctaUrl" href="/demo">Book a demo</a>
|
|
28
|
+
</section>
|
|
29
|
+
</body>
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The anti-flicker snippet is also exported as `ANTI_FLICKER_SNIPPET`.
|
|
33
|
+
|
|
34
|
+
## Bundlers
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
import { init, setConsent, conversion } from "@kharon-labs/browser";
|
|
38
|
+
|
|
39
|
+
init({ key: "ge_pk_…" });
|
|
40
|
+
myCmp.onChange((ok) => setConsent(ok ? "granted" : "denied"));
|
|
41
|
+
conversion("demo_booked");
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
| Function | What it does |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| `init({ key, apiBase?, consent?, timeoutMs?, pageId?, cookieDomain? })` | Resolves the page's slots once the DOM is ready and starts measuring if allowed. |
|
|
47
|
+
| `setConsent("granted" \| "denied" \| "unknown")` | Forward your consent tool's answer. Safe to call before `init`. |
|
|
48
|
+
| `conversion(goal, value?)` | Records a goal. Forms with `data-ge-goal="…"` record theirs on submit. |
|
|
49
|
+
| `signup()` | Records a `signup` conversion. Prefer `recordSignup` in `@kharon-labs/server`, which counts only signups that succeeded. |
|
|
50
|
+
| `refresh()` | Re-scans and re-resolves, e.g. after a client-side route change. |
|
|
51
|
+
|
|
52
|
+
## Slots
|
|
53
|
+
|
|
54
|
+
- `data-ge-slot="id"` marks a slot; the id matches a slot in the console. Repeat an id to show the
|
|
55
|
+
same decision in several places.
|
|
56
|
+
- `data-ge-field="name"` writes a content field as text (`textContent`), never as HTML.
|
|
57
|
+
- `data-ge-attr="href:ctaUrl, title:ctaTitle"` writes fields into attributes. URL attributes accept
|
|
58
|
+
only `http(s)` and relative links; event handlers and `style` are never written.
|
|
59
|
+
- The markup's own text is the default. A field the variant doesn't set keeps it, and a slot the
|
|
60
|
+
console doesn't know yet keeps all of it.
|
|
61
|
+
|
|
62
|
+
## Single-page apps
|
|
63
|
+
|
|
64
|
+
The package scans the page once, when the DOM is ready. After a client-side route change that mounts
|
|
65
|
+
new slots, call `refresh()`. On React Native Web, a `dataSet={{ geSlot: "hero" }}` prop renders
|
|
66
|
+
`data-ge-slot="hero"`; React Native's types don't declare `dataSet`, so add it with a module
|
|
67
|
+
augmentation (or use `@kharon-labs/react`, which needs no DOM attributes).
|
|
68
|
+
|
|
69
|
+
## Guarantees
|
|
70
|
+
|
|
71
|
+
- **Defaults always render.** If we answer late (after `timeoutMs`, 500 ms), fail or are down, the
|
|
72
|
+
page keeps its defaults and slots are revealed. The package never retries.
|
|
73
|
+
- **Consent is decided by our server**, by the visitor's country and choice (opt-in in the EEA, UK
|
|
74
|
+
and Switzerland, GPC honored). Until it allows storing the visitor, the package writes no cookie
|
|
75
|
+
or storage and sends no analytics.
|
|
76
|
+
- **Holdouts.** Held-out visitors see the defaults; their impressions record the variant withheld.
|
|
77
|
+
- **Acquisition.** A session's first page view records how it arrived: `utm_*` tags, which ad
|
|
78
|
+
network's click id was present (never the id), a Kharon campaign link, and the referring site's
|
|
79
|
+
host. Never the URL's path or other parameters.
|
|
80
|
+
|
|
81
|
+
The visitor id is a first-party `ge_vid` cookie on your domain (one year; Safari caps script-set
|
|
82
|
+
cookies at seven days, `@kharon-labs/server` avoids that). A denial deletes it.
|
|
83
|
+
|
|
84
|
+
## Size and support
|
|
85
|
+
|
|
86
|
+
About 4 KB gzip, no dependencies. ES2020 browsers; without `fetch` the page keeps its defaults, and
|
|
87
|
+
without `IntersectionObserver` impressions aren't recorded.
|
|
88
|
+
|
|
89
|
+
## Your privacy policy
|
|
90
|
+
|
|
91
|
+
Adding Kharon Labs sets a first-party cookie and sends visit data to us, so your
|
|
92
|
+
privacy policy should say so. A paragraph to adapt (not legal advice):
|
|
93
|
+
|
|
94
|
+
> We use Kharon Labs to tailor parts of this website to the organization a visit comes from and to
|
|
95
|
+
> measure whether that helps. Kharon Labs processes your IP address, browser details, the page you
|
|
96
|
+
> visit and how you arrived, and infers your organization (not you personally). With your consent
|
|
97
|
+
> where required, it stores a random visitor ID in a first-party cookie (`ge_vid`) and records page
|
|
98
|
+
> views and interactions. See https://kharonlabs.com/privacy for what Kharon Labs collects and how
|
|
99
|
+
> long it keeps it.
|