Integration
Hand the packet to your IT team. Five steps; the email below is pre-written and waiting for one click.
Send to your IT team
Fill the four fields. We generate a self-contained email — your IT person never needs to read this dashboard.
Used as the default in the snippet. Your IT team / customers can override per-call.
Allowed origins
One per line. Wildcards allowed (https://*.yourapp.com). The browser only fetches a recommendation when the embedding page's origin is on this list.
Check connection
Paste any URL to verify it'll be accepted. Then click 'Open preview' to see the actual widget render.
Paste your widget key in Step A to enable preview.
Code snippets (if you prefer to copy directly)
Same code that lands inside the email packet. Replace QLRO_KEY env reference with your widget key, or use the React component as-is.
import { QlroRecommend } from "@qlro/embed/react";
export function YourFeature() {
return (
<QlroRecommend
partnerKey={process.env.NEXT_PUBLIC_QLRO_KEY!}
workload={{ template: "chemistry.lih_ground_state" }}
theme="auto"
lang="en"
onRecommendation={(rec) => {
// hand off to your CRM / lead-routing
}}
/>
);
}<div id="qlro"></div>
<script type="module">
import { attach } from "https://esm.sh/@qlro/embed@0.1.0";
attach({
target: document.getElementById("qlro"),
partnerKey: "qlro-pkw_...",
workload: { template: "chemistry.lih_ground_state" },
theme: "auto",
});
</script><iframe src="https://partner.qlro.io/embed/recommend?partner_key=qlro-pkw_...&template=chemistry.lih_ground_state&theme=auto" style="width:100%;border:0;min-height:280px" title="Qlro recommendation" ></iframe>
Test from https://yourapp.com to confirm the allowlist + key combination is live.
Webhook signature verification
If you wire webhooks (Step F on /partner/webhooks), verify every payload with HMAC-SHA256 before trusting it. Snippets your IT team can paste verbatim.
Header: X-Qlro-Signature · Algorithm: HMAC-SHA256 over the raw request body, using the project's webhook_secret. Use a constant-time comparison.
import hmac, hashlib
def verify_qlro_signature(secret: str, body: bytes, signature: str) -> bool:
"""Constant-time HMAC-SHA256 verification.
Pass the raw request body bytes (do NOT json.loads first) — the
signature is computed over the exact bytes Qlro sent.
"""
expected = hmac.new(
secret.encode("utf-8"),
body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)const crypto = require("crypto");
function verifyQlroSignature(secret, body, signature) {
// body must be the raw bytes, not a JSON-parsed object.
// In Express: app.use(express.raw({ type: "application/json" }));
const expected = crypto
.createHmac("sha256", secret)
.update(body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature),
);
}import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
)
func VerifyQlroSignature(secret string, body []byte, sigHex string) bool {
mac := hmac.New(sha256.New, []byte(secret))
mac.Write(body)
expected := hex.EncodeToString(mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(sigHex))
}