Causiq's SDK is a complement to our Media Mix Modelling (MMM). MMM is at the core a top-down method, in that it spans from marketing spend, to impressions (of the ads), all the way through to the measured goal/revenue (the KPI).
In contrast, the data that can be captured from your web properties or apps (also called a clickstream) can be used to give you granular insights about the number of visitors, which pages are popular, whether that popularity is also causatively linked to an increase in your measured KPI.
As such, the SDK and the MMM that we run using the marketing spend data are very strong complements to each other. In a way, if you have desirable products, the parameters of the function that explains how well your marketing is doing, is primarily:
- the content and its quality
- optimising between channels and on funnel level
- optimising the site with uplift modelling
As such, the SDK further strengthens the analysis that we can perform on your behalf, and truly makes Causiq the Marketeer's control panel.
A GDPR-friendly Google Analytics
Causiq's SDK was designed with GDPR in mind. It has a few different key features. To start with, the SDK has a complete API for forgetting and/or resetting user identifiers. Forgetting can be used by the user on the site itself, and the resetting feature lets you easily track computers used by multiple persons.
Furthermore, you can run Causiq's SDK in a cookieless mode. Then the pseudo-anonymous identifier is only bound to the current browser session and will be forgotten when the user closes the tab.
If you don't use the identify
or setUserProps
functions, then by default, only a persistent, first-party, pseudo-anonymous identifier is written to the cookie jar and hrefs are logged from the browser. As such, there's no obvious way to tie this data to a specific user.
Finally and most importantly, Causiq AB is a Swedish company, so your data doesn't leave the European Union.
Setup
In the app, go to Settings > Pixel
and follow the instructions to add the pixel to your site or app.
In GTM or as a pixel
Inside your <head>
tag:
<script> window.causiq=window.causiq||[], causiq.init=function(m, c) { causiq.push(['init', m, c]); var s = document.createElement("script"); s.type = "text/javascript", s.async = !0, s.src = "https://api.causiq.com/v1/track/causiq.js"; var a = document.getElementsByTagName("script")[0]; a.parentNode.insertBefore(s, a); for (var n = function(e) { return function() { causiq.push([e].concat(Array.prototype.slice.call(arguments, 0))) } }, p = [ "init", "track", "error", "setPageProps", "setUserProps", "unsetUserProps", "getIdentity", "identify", "resetIdentity", "forgetUser", "navigate"], i = 0; i < p.length; i++) causiq[p[i]] = n(p[i]) }; causiq.init("CQ-H1A23LDP9ABC"); </script>
With NodeJS
If you want to use the NodeJS CommonJS module, you can install it using:
npm i @causiq/sdk
or if you're using yarn
yarn add @causiq/sdk
Example
import { Causiq } from '@causiq/sdk' const c = new Causiq() c.init('CQ-H1A23LDP9ABC')
Lifecycle
-
init(moniker: string, config?: Partial<Config>): void
-
This function call is a requirement in order to initialise Causiq.
causiq.init('CQ-H1A23LDP9ABC')
Alternatively if you want to initialise with a configuration:
causiq.init('CQ-H1A23LDP9ABC', { cookieless: false, disableTextCapture: false, })
...or if you want to test with only the console client-side to start with:
const c = new Causiq() c.init('CQ-H1A23LDP9ABC', (config, { sendWithConsole }) => ({ send: typeof window === 'undefined' ? config.send : sendWithConsole, }))
You can read more about the configuration options further below.
causiq
with the API documented below.
Config properties
Configuration properties specify how Causiq's SDK performs/acts.
disableTextCapture: boolean
-
The disableTextCapture option will stop Causiq from capturing contents from your pages. By default, Causiq does not capture the contents of input fields, but captures text from most other elements. You can get more granular tracking by supplying a function to the
shouldCaptureText
property of the configuration. shouldCaptureText(element: Element): boolean
-
This function will then be called for every click; return
true
if the text can be captured. If you override this function, ensure you don't capture sensitive data.causiq.init('CHANGE-ME', { shouldCaptureText: function shouldCapture(el) { return ['button'].indexOf(el.localName) !== -1 }, })
sendInterval: number
- How often in milliseconds, to broadcast the list of messages to be tracked.
send(messages: InternalMessage[]) => Promise<void>
-
Lets you configure (for unit testing, or for novel runtimes), how to send the tracking data.
sendWithConsole
: only send to the consolesendWithBeacon
: send to api.causiq.com with beaconsendWithFetch
: send to api.causiq.com with fetch
cookieName: string
- Useful if you want to let Causiq read your own user id cookie (remember the cookie must only contain a 32 char long string)
cookieless: boolean
-
Whether to run the SDK in a fully cookieless manner; in which case it'll generate a new pseudo-anonymous identifier that is active while the script is loaded and then forgotten. You can use
identify
to link this session with a persistent user id. -
id
attributes -
data-track
attributes -
class
attributes - the name of the element, e.g.
section
startSpan(name: string): StartedSpan
- You can use this function to start child spans; it logs a minimal format of OpenTelemetry. Useful if you're interested in understanding how long your users have modal dialogs open, for example.
end(): void
- Ends the current span (that was returned from startSpan).
setPageProps(props: Props, spanContext?: SpanContext): void
- Useful for categorising pages to see which type of page attributes causes better KPI:s
Example
<button onClick="causiq.setPageProps({title:window.document.title})">Set page props</button>
track(name: string, props?: Props, spanContext?: SpanContext): void
- This is the primary method for tracking user interactions and details about e.g. products in an e-commerce shop.
Example
<button onClick="causiq.track('Add to cart', {a:1})">Add to cart</button>
navigate(prevHref: string, nextHref: string, props?: Props, spanContext?: SpanContext): void
- Track navigation events that don't cause page reloads (e.g. modern JS apps)
Example
<button onClick="causiq.navigate(window.location.href, 'https://causiq.com/')">Navigate</button>
error(err: Error | ErrorEvent | string, props?: Props, spanContext?: SpanContext): void
- Log
Error
,ErrorEvent
orstring
messages as errors.Example
<button onClick="(function(){throw new Error('Example error')})()">Throw error</button>
identify(newId: string, spanContext?: SpanContext): void
-
Links the current pseudo-anonymous identifier created by Causiq's SDK with another identifier.
Example
<button onClick="causiq.identify('cb36c6eb59f24c54aafc7e7d9d893509')">identify</button>
getIdentity(): UserId
- This function call will return the identity of the current user
Example
<button onClick="alert(causiq.getIdentity())">getIdentity</button>
resetIdentity(): UserId
-
This function call will reset the identity of the current user, and return the new
user id. Useful if you're tracking websites that may be used on shared computers.
Example
<button onClick="causiq.resetIdentity()">resetIdentity</button>
setUserProps(props: Props, spanContext?: SpanContext): void
- Associate key-value pairs/attributes/properties with the current user.
Example
<button onClick="causiq.setUserProps({nickname: 'haf'})">setUserProps({ nickname: 'haf' })</button>
unsetUserProps(...keys: string[]): void
- Disassociate the keys from the user.
Example
<button onClick="causiq.unsetUserProps('nickname')">unsetUserProps('nickname')</button>
ts: number
- A Unix epoch Timestamp in milliseconds when the event occured.
v: string
- The version string of the SDK, in the form Major.Minor.Patch.Timestamp
m: string
- Compilation mode of the sdk.
Accepted values: prod t: string
- Compilation target.
Accepted values: web | node payload: array
- An array with all the messages to send
m: string
- App moniker that uniquely identifies the app in Causiq
t: number
- The timestamp epoch milliseconds of this event
n: string
- The name of the event that is sent
Accepted values:
Each of these carry different data that should be sent inps
Common page tracking examples:
*** for more event types please visit our event documentation here
clicked
{ cssSelector: string, eventName?: string, text?: string }
pageVisible
;[VisibilitySource, PageData]
VisibilitySource:
load | visibilitychange | pagehide | unload | navigate,
PageData:
{ /** * Identifies which site sent the traffic, and is a required parameter. */ utmSource?: string | null /** * Identifies what type of link was used, such as cost per click or email. */ utmMedium?: string | null /** * Identifies a specific product promotion or strategic campaign. */ utmCampaign?: string | null /** * Identifies search terms. */ utmTerm?: string | null /** * Identifies what specifically was clicked to bring the user to the site, such as a banner ad or a text link. It is often used for A/B testing and content-targeted ads. */ utmContent?: string | null /** * Google Ads click Id */ gclid?: string | null /** * navigator.location.href: the full URL of the page/screen. * Can also be a URI. */ readonly href: string /** * the pathname part of the URL */ readonly pathname: string /** * The title of the page/screen. */ readonly title: string /** * max(document.documentElement.clientWidth, window.innerWidth) * https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth * https://developer.mozilla.org/en-US/docs/Web/CSS/Viewport_concepts */ readonly clientWidth: number /** * max(document.documentElement.clientHeight, window.innerHeight) * https://developer.mozilla.org/en-US/docs/Web/API/Element/clientWidth * https://developer.mozilla.org/en-US/docs/Web/CSS/Viewport_concepts */ readonly clientHeight: number /** * navigator.userAgent */ readonly userAgent: string /** * max(window.screen.width, window.screen.availWidth) */ readonly deviceWidth: number /** * max(window.screen.width, window.screen.availWidth) */ readonly deviceHeight: number /** * document.referrer (may be the empty string). */ readonly referrer: string | null /** * Olsen timezone */ readonly timezone: string | null /** * new Date().getTimezoneOffset() which gives the offset of UTC * from the perspective of the User's browser. */ readonly datetimeOffset: number /** * Browser or device vendor */ readonly vendor: string | null /** * Which languages are enabled in the User's browser? */ readonly languages: readonly string[] }
pageHidden
;load | visibilitychange | pagehide | unload | navigate
spanEnd
{ /** * A reference to the SpanContext this Span belongs to. */ readonly context: SpanContext /** * The operation name. E.g. if the UI spawns a modal, the name of the modal could be the * operation name. */ readonly name: string /** * When did this Span start? ms since epoch */ readonly start: Timestamp /** * Which type of Span is this? */ readonly kind: SpanKind /** * Span attributes used to provide the context the span was created and used in for human consumption. */ readonly attrs: Props /** * This span does not have an error. */ ok: boolean /** * When (if ever) did this Span end? Server-side, this is a required value. */ end?: Timestamp }
ps: array | tuple
- An array/tuple, typed specifically for the type of message denoted by discriminator prop
n
. s: SpanContext
- A SpanContext is a simple DTO that tracks the overarching Trace Id as well as the current
Span Id. More docs at opentracing.io
spanId: string
- The 16 character Span Id. The Id of the Span. It is globally unique with practically sufficient probability by being made as 8 randomly generated bytes, encoded as a 16 lowercase hex characters corresponding to 64 bits.
parentSpanId?: string
- A optional 16 character Parent span Id.
traceId: string
- The 32 character Trace Id The Id of the trace that this span belongs to. It is worldwide unique with practically sufficient probability by being made as 16 randomly generated bytes, encoded as a 32 lowercase hex characters corresponding to 128 bits.
traceFlags: number
-
It is represented as 1 byte (bitmap). Bit to represent whether trace is
sampled or not. When set, the least significant bit documents that the
caller may have recorded trace data. A caller who does not record trace
data out-of-band leaves this flag unset.
Available values:
0: None
1: Sampled
u: string
- By default, a 32 characters (128 bits) long hexadecimal string denoting a User Id.
-
Order Completed (minimal) payload:
{ "ts": 1666897447941, "v": "2.0.0.1666786511242", "m": "prod", "t": "node", "payload": [ { "m": "CQ-H1A23LDP9ABC", "t": 1666897447938, "n": "track", "ps": ["Order Completed", { "orderId": "order-123", "total": 27, "currency": "EUR" }], "s": { "spanId": "eeb77dc8554d4ca3", "traceId": "132f9f36f634457cafc7b81c44d334c0", "traceFlags": 1 }, "u": "77c3b9fbbf35406fbd416556fc992d68" } ] }
-
Order Completed (complete) payload:
{ "ts": 1666897447941, "v": "2.0.0.1666786511242", "m": "prod", "t": "node", "payload": [ { "m": "CQ-H1A23LDP9ABC", "t": 1666897447938, "n": "track", "ps": ["Order Completed", { "checkoutId": "456", "orderId": "order-123", "products": [{ "productId": "987", "sku": "789", "name": "Product 1", "price": 10, "salesPrice": 8, "quantity": 3, "category": "Category 1", "url": "https://example.com/product-1", "imageUrl": "https://example.com/product-1.jpg" }], "subtotal": 24, "tax": 6, "discount": 3, "total": 27, "currency": "EUR", "coupon": "ERIKA2021Q3" }], "s": { "spanId": "eeb77dc8554d4ca3", "traceId": "132f9f36f634457cafc7b81c44d334c0", "traceFlags": 1 }, "u": "77c3b9fbbf35406fbd416556fc992d68" } ] }
-
Account Created payload:
{ "ts": 1666897447941, "v": "2.0.0.1666786511242", "m": "prod", "t": "node", "payload": [ { "m": "CQ-H1A23LDP9ABC", "t": 1666897447938, "n": "track", "ps": ["Account Created", { "accountId": "account-123", "accountName": "Acme Inc" }], "s": { "spanId": "eeb77dc8554d4ca3", "traceId": "132f9f36f634457cafc7b81c44d334c0", "traceFlags": 1 }, "u": "77c3b9fbbf35406fbd416556fc992d68" } ] }
Automatic click tracking
Causiq's SDK automatically tracks clicks by their CSS selector based on element names, class attributes and ids. This can be used after-the-fact to assign event names to selectors (virtual events). It will prefer to track a more specific selector over less specific (you can try clicking these list items):
NOTE: data-track
is meant for event names
primarily; if you want better CSS Selectors, use the id
attribute.
Tracing
The tracing functionality is at the core of the SDK; every time you show a page/hide a page a span is generated and sent to the tracking endpoint.
Content analytics
Behavioural analytics
User data platform
SDK API
If you are not able to use our javascript sdk for some reason. Maybe you are building a native app and can't use javascript. Then you can use our API directly like so.
The main endpoint is the track
endpoint.
To which you will use the HTTP verb POST
to send application/json
data.
Example
POST https://api.causiq.com/v1/track
Content-Type: application/json
Accept: */*
Causiq Semantic Events
Causiq currently provide semantic events for ecommerce and bussiness to bussiness software as a service. And this is currently beeing developed, so more will come.
Documentation and examples of the Causiq semantic events can be found here:
Payload outline
Below is a desciption of a track event payload.
Example of SDK-evens payloads
Below are to two most common events, Order Completed and Account created, listed with their corresponding payloads.
which will yield a successful 200 Ok
response like so:
{ "error": false, "message": "ok" }
or a 400 Bad Request
response:
{ "error": true, "message": "Failed schema validation", "payload": [ { "instancePath": "", "schemaPath": "#/required", "keyword": "required", "params": { "missingProperty": "m" }, "message": "must have required property 'm'" } ], "input": { "ts": 1666897447941, "payload": [ { "m": "CQ-H1A23LDP9ABC", "t": 1666897447938, "n": "pageHidden", "ps": [ "visibilitychange" ], "s": { "spanId": "eeb77dc8554d4ca3", "traceId": "132f9f36f634457cafc7b81c44d334c0", "traceFlags": 1 }, "u": "77c3b9fbbf35406fbd416556fc992d68" } ] } }
What's next?
You’re here for answers, we’re here to help.