Flonk
Flonk Docs

Troubleshooting

Common issues and solutions

Last updated: 8/19/2026
5 min read

Troubleshooting

Solutions for common KYC integration issues.

SDK Issues

Module Not Found

Symptom: Cannot find module '@flonkid/kyc'

Solution: Install the SDK:

npm install @flonkid/kyc
bash

SSR Error (Next.js)

Symptom: window is not defined or document is not defined

Solution: Use dynamic import to avoid SSR:

// Wrong: top-level import runs on server
import { FlonkKYC } from '@flonkid/kyc';
// Correct: dynamic import runs only in browser
const startKYC = async () => {
const { FlonkKYC } = await import('@flonkid/kyc');
const kyc = new FlonkKYC();
// ...
};
typescript

serverUrl HTTPS Error

Symptom: serverUrl must use HTTPS in production

Solution: The SDK enforces HTTPS for absolute URLs. Use a relative path or HTTPS:

// Relative path (OK)
serverUrl: '/api/kyc/create-session'
// HTTPS (OK)
serverUrl: 'https://api.myapp.com/kyc/create-session'
// HTTP (rejected, except localhost)
serverUrl: 'http://api.myapp.com/kyc/create-session' // Error!
typescript

Widget / Loader Issues

Turn on debug logging first

Before anything else, make the SDK tell you what it's doing. Every degradation (blocked loader script, prewarm skipped, no READY from the iframe, protocol mismatch) is reported — silent by default, visible when you opt in:

// Anywhere before the widget opens — no rebuild needed:
window.__FLONK_DEBUG__ = true;
// Or capture events in code:
const kyc = new FlonkKYC({
onDiagnostic: (e) => console.log(`[flonk:${e.code}] ${e.message}`, e.detail),
});
typescript

For the classic <script src=".../widget.js"> loader, add data-debug to the tag (or set the same global). Then reproduce and read the [flonk:*] codes.

Loader stuck / widget never appears

Symptom: the loading overlay stays up; the widget content never shows.

Diagnose: enable debug logging (above) and look for:

CodeCauseFix
READY_TIMEOUT_REVEALThe iframe never sent READY (usually a CSP frame-src block or a hard error inside the iframe).Allow https://widget.flonk.id in frame-src (see below); check the iframe's own console.
LOADER_SCRIPT_BLOCKEDThe branded loader script was blocked (CSP script-src, CORP, or offline).Allow https://api.flonk.id in script-src. The SDK still works with its bundled loader.
PROTOCOL_VERSION_MISMATCHThe SDK and the cached iframe speak different wire versions.Hard-refresh / clear the site's cache to drop the stale widget.

The SDK reveals the widget on a safety timeout even if READY is missing, so a permanent "stuck loader" should not happen — if it does, it's almost always a frame-src CSP block stopping the iframe from loading at all.

Content Security Policy (CSP) blocks the widget

Symptom: the iframe or loader script is blocked; console shows a CSP violation or ERR_BLOCKED_BY_RESPONSE.

Solution: if your site sends a Content-Security-Policy, allow our origins:

Content-Security-Policy:
frame-src https://widget.flonk.id;
script-src https://widget.flonk.id https://api.flonk.id;
connect-src https://api.flonk.id https://widget.flonk.id;
img-src https://widget.flonk.id data:;

You do not need any CORS or Cross-Origin-Resource-Policy config on your side — our public assets already send the right cross-origin headers, and the API handles CORS for the SDK's requests. If the loader script specifically is blocked, the SDK falls back to its bundled loader and still works (you just lose dashboard-driven loader branding).

API Issues

401 Unauthorized

Symptom: invalid_api_key error.

Checklist:

  • Using correct secret key (not publishable key)
  • Key is for correct environment (test/live)
  • Bearer prefix in Authorization header
  • No extra spaces in key
// Correct
headers: {
'Authorization': `Bearer ${secretKey}`,
}
// Wrong
headers: {
'Authorization': secretKey, // Missing Bearer
'Authorization': `Bearer ${secretKey} `, // Extra space
}
typescript

400 Bad Request

Symptom: Request validation errors.

Common causes:

  1. Invalid or missing data:
{
"clientMetadata": {
"email": "user@example.com", // recommended
"userId": "user_123" // optional
}
}
// All clientMetadata fields are optional, but email is
// recommended so webhook events can be matched to users.
typescript
  1. Invalid JSON:
// Use JSON.stringify
body: JSON.stringify(data)
// Not
body: data
typescript

Webhook Issues

Webhooks Not Received

Checklist:

  • Endpoint is publicly accessible (not localhost)
  • HTTPS enabled
  • URL registered in Flonk Dashboard
  • Server returns 200 OK

Test with ngrok for local development:

ngrok http 3000
# Use ngrok URL in Dashboard
bash

Invalid Signature

Symptom: Signature verification fails.

Solutions:

  1. Use raw body, not parsed JSON:
// NestJS - enable raw body
app.useGlobalPipes(new ValidationPipe());
app.use(json({ verify: (req, res, buf) => {
req.rawBody = buf;
}}));
typescript
  1. Verify correct webhook secret
  2. Pass the right header — X-Signature (recommended, replay-protected) or the X-Signature-256. constructEvent accepts either. If you verify manually, use a constant-time compare (crypto.timingSafeEqual), not ===.

Duplicate Webhooks

Symptom: Same event processed multiple times.

Cause: delivery is at-least-once (Flonk retries on non-200), so duplicates are expected. Dedupe by event.id in your own store — a unique DB index or Redis SET NX:

const fresh = await redis.set(`whk:${event.id}`, '1', 'PX', 6 * 60_000, 'NX');
if (fresh === null) return; // retry — already handled
await processEvent(event);
typescript

See Webhooks → Idempotency for the DB-unique-index variant.

Getting Help

If you can't resolve an issue:

  1. Check Integration Guide
  2. Check API Reference
  3. Contact support: support@flonk.id

Include in support requests:

  • Session ID
  • Error messages
  • Timestamp
  • Request/response logs (without sensitive data)

Need Help?

Get in touch with our team for technical support.

Contact Support