@loopcheck/qa-sdk
v1.0.1
Published
Loopcheck browser SDK for element identity and session recording
Readme
@loopcheck/qa-sdk
Browser instrumentation for Loopcheck. The SDK answers two questions:
- What did the user interact with?
- How do we identify that element stably?
It does not generate Playwright tests — that belongs to the Loopcheck automation engine.
Installation
pnpm add @loopcheck/qa-sdkPeer dependency: react >= 18 (only if you use @loopcheck/qa-sdk/react).
Quick start (publishable key)
- In Loopcheck → Project settings → Publishable keys, create a key (
lc_pk_…). - Wrap your app. The SDK stays inert until you call
startRecording()(safe behind a login wall).
"use client";
import { QAProvider, useQA } from "@loopcheck/qa-sdk/react";
export function Providers({ children }: { children: React.ReactNode }) {
return (
<QAProvider
config={{
apiUrl: "https://api.loopcheck.dev", // your Loopcheck API origin
publishableKey: process.env.NEXT_PUBLIC_LOOPCHECK_KEY!,
// default: inert until startRecording()
startOn: "manual",
}}
>
{children}
</QAProvider>
);
}
function RecordToolbar() {
const { startRecording, stopRecording, isRecording } = useQA();
return (
<button
type="button"
onClick={() => void (isRecording ? stopRecording() : startRecording())}
>
{isRecording ? "Stop" : "Record"}
</button>
);
}startRecording():
POST /v1/sdk/sessionswith the publishable key (no Loopcheck login cookie).- Attaches listeners and posts events to
/v1/sdk/events.
Auth gate
Keep the provider mounted for all visitors. Call startRecording() only after the user is logged into your app (or from an internal QA toolbar). Until then the SDK does not attach listeners or make network calls.
To arm from the URL instead:
<QAProvider
config={{
apiUrl: "https://api.loopcheck.dev",
publishableKey: process.env.NEXT_PUBLIC_LOOPCHECK_KEY!,
startOn: "query", // starts when ?lc_record=1
}}
>Configuration
| Field | Default | Purpose |
|---|---|---|
| publishableKey | — | Durable browser key (lc_pk_…) from project settings |
| apiUrl | "" | Loopcheck API origin |
| projectId | resolved on session create | Optional; filled from the key response |
| sessionId | — | Pre-minted session (extension / dashboard flow) |
| publicClientToken | — | Alias / legacy session token (lc_pub_…) |
| startOn | manual | manual | query (?lc_record=1) |
| enabled | true | Master switch |
| mode | inert for key-only installs | disabled | observe | record |
| debug | false | Inspector overlay (Alt+Shift+hover) |
| recordInputValues | false | Values are [REDACTED] unless true and not sensitive |
| transport | HTTP | Replaceable QATransport |
All config is passed explicitly. The SDK never reads DATABASE_URL, SESSION_SECRET, or other server secrets.
React helpers
import { QAProvider, useQA, useQAElement, QAButton } from "@loopcheck/qa-sdk/react";
function CheckoutButton() {
const ref = useQAElement("checkout.continue");
return <button ref={ref}>Continue</button>;
}Or stamp the DOM yourself:
<button data-qa-id="checkout.continue">Continue</button>Privacy
Always redacted: passwords, data-qa-sensitive, card/CVV-like fields, and redactSelectors. Fetch uses credentials: "omit". Cookies and authorization headers are never collected.
Extension / dashboard recording
The Chrome extension and Loopcheck record UI still mint one-shot lc_pub_… session tokens via recordings.create. That path is unchanged. Prefer publishable keys for embedding the SDK in a customer app.
Troubleshooting
| Symptom | Fix |
|---|---|
| Empty recordings | Call startRecording() after login, or set startOn: "query" with ?lc_record=1 |
| 401 on session create | Check the publishable key and optional origin allowlist |
| Hydration warnings | Keep QAProvider in a Client Component |
| Network errors in console | Swallowed by default; use onError |
License
Proprietary — UNLICENSED. Not open source.
