Attribution and Events
Install first-party attribution, identify customers, and ingest trusted conversions or revenue.
LinkQuick connects redirects, external customer identifiers, events, conversions, and revenue through first-party last-touch attribution. Browser events use a publishable site key. Trusted server events use a secret Admin API key. Never put an Admin API key in browser code.
Create a tracking site
Open Organization → Attribution, then create one tracking site for each destination application or group of applications that share the same allowed origins.
- Give the site a recognizable name.
- Add every production hostname that may send browser events. Enter hostnames without paths; full URLs are accepted and normalized.
- Add preview, staging, or local hostnames explicitly when they need tracking. Wildcards are not accepted.
- Choose an attribution window from 7 to 90 days. The default is 30 days.
A site accepts up to 20 hostnames. When a visitor lands on one domain and converts on another, read Multi-Domain Attribution before deciding whether to create a second site.
LinkQuick creates a publishable key and a copy-ready configuration snippet immediately. The key is intentionally public and allowed origins protect ordinary browser use; they are not proof that an event is trusted. Treat browser events as product telemetry, and send conversions, entitlements, and revenue from your authenticated backend. Disable the tracking site to revoke browser ingestion without deleting historical attribution.
Install the browser SDK
Copy the generated snippet from Organization → Attribution. The hosted, framework-free client works in any browser application without a package-registry login or build dependency:
<script src="https://linkquick.melvynx.dev/linkquick.js"></script>
<script>
const linkquick = LinkQuick.create({
endpoint: "https://linkquick.melvynx.dev/tracking",
publishableKey: "lq_pk_YOUR_PUBLISHABLE_KEY",
attributionWindowDays: 30,
});
</script>The endpoint is https://linkquick.melvynx.dev/tracking, a first-party path on
LinkQuick itself that forwards to the tracking backend. Keep it as generated;
the backend host is an implementation detail and may change.
By default, initialization captures lf_id from the current URL, stores it in
first-party localStorage, and removes only that parameter from the visible
URL. Other query parameters and the URL fragment are preserved.
Load the script in the browser before initializing it. You can also pass a
compatible storage implementation. Set captureOnInit: false only when the
application calls linkquick.capture() itself.
The conversion funnel
LinkQuick models attribution as three steps, in the same order as the visit itself:
- Click — the redirect records a click and hands
lf_idto the destination application, where the SDK stores it first-party. - Lead — the first moment you learn who the visitor is. An email from a form is enough; a signed-in user ID is better. The lead binds the stored click to a customer.
- Sale — revenue for a customer that already has a lead. Every sale inherits the link attribution the lead established.
Only the lead step needs the click ID, so it must run in the browser (or receive
a clickId you forwarded to your backend). Sales are pure server calls keyed by
the customer.
Capture a lead
Use lead when the application does not have a user ID yet — a newsletter
form, a waitlist, a demo request. The email becomes the customer key.
await linkquick.lead("melvyn@example.com", {
name: "Melvyn",
eventName: "Sign up",
metadata: { form: "newsletter" },
});trackLead is the full form when you have both an email and your own ID:
await linkquick.trackLead({
externalCustomerId: currentUser.id,
customerEmail: currentUser.email,
customerName: currentUser.name,
eventName: "Trial started",
idempotencyKey: `lead:${currentUser.id}`,
});eventName defaults to Sign up. When externalCustomerId is omitted the
normalized email is used as the customer key, so the same address always
resolves to the same customer.
A customer is identified by that key alone; LinkQuick does not merge two customers because they share an email. Pick one key per person — the email until an account exists, then your own user ID — and pass it consistently.
Browser leads require a real, unexpired click ID. A form submit from a visitor who never clicked a LinkQuick link is rejected rather than recorded as an unattributed customer. Send those from the server instead.
Identify a customer
Call identify after the destination application knows its stable internal
customer identifier. Prefer an internal ID over an email here; use lead when
the email is all you have.
const result = await linkquick.identify(currentUser.id, {
idempotencyKey: `identify:${currentUser.id}`,
});
if (!result.ok) {
console.error(result.code, result.retryAfter);
}The SDK attaches the most recent eligible click and remembers the customer ID for subsequent browser events.
Track a browser event
await linkquick.track("signup.completed", {
metadata: {
plan: "pro",
source: "onboarding",
},
idempotencyKey: `signup.completed:${currentUser.id}`,
});Browser ingestion accepts named product events, but it deliberately rejects trusted conversion revenue. Send conversions and money from a server.
Verify the installation
- Open an active short link in a new browser session.
- Confirm the destination initially receives
lf_idand the SDK then removes it from the visible address. - Confirm
linkquick:attributionexists in first-party local storage. - Sign in or complete the identified action in the destination application.
- Open the LinkQuick parent link. Its detail page shows whether attribution is configured, and its Analytics page shows identified users and events.
- Open Customers to inspect the attributed journey.
An invalid_key response means the key does not exist or the site is disabled.
A forbidden_origin response means the request's exact hostname is missing
from the tracking site. A rate_limited response includes retryAfter in
milliseconds.
List customers
curl "https://linkquick.melvynx.dev/api/v1/customers?limit=50" \
-H "Authorization: Bearer $LINKQUICK_API_KEY"Add linkId=LINK_ID to return customers currently attributed to one link.
Read a customer journey
The path uses your application's stable external customer ID, URL encoded when necessary:
curl "https://linkquick.melvynx.dev/api/v1/customers/customer_123" \
-H "Authorization: Bearer $LINKQUICK_API_KEY"