Steeren/Troubleshooting & gotchaslive from the platform← site
Operate

Troubleshooting & gotchas

This page collects the snags people most often hit with a Steeren-managed site - content that won't show, forms that don't reach your CRM, rate limits, stuck sends, and deploys that stall. Each entry names the symptom, the likely cause, and what to do about it.

Most issues fall into one of two buckets:

  • Non-technical: something on your site looks wrong (no content, a form sitting on "loading", a post that cuts off). Usually a domain or republish question - start there.
  • Self-hosting / integrating: you've wired your own site to Steeren with @nukipa/site-sdk. A few platform contracts (the host you forward, the relay you call through) have to be right or content silently resolves to the wrong place.

Content not showing, or the wrong content showing

Steeren figures out which site to serve from the visitor's domain. If that domain doesn't map to your workspace yet, you'll see a "not found" page for a single post, or an empty list where your posts should be - never someone else's content.

You're not technical / using a Steeren-managed site:

  • My custom domain shows "not found", but the temporary Steeren address works. Your domain isn't verified yet. Until DNS finishes verifying, only the temporary your-name.nukipa.io-style address resolves. Check the domain status in your dashboard and confirm the DNS records are in place.
  • www. and the bare domain behave differently. Treat them as two separate addresses. Either verify both in your dashboard, or pick one as canonical and redirect the other to it at your domain/DNS provider.

You're self-hosting your own site:

  • Everything is empty when the site builds or renders at the edge, but fine in a normal browser. Build-time and edge renders don't carry an incoming request, so there's no visitor host to read. That's what NUKIPA_TENANT_HOST is for - set it to your Steeren platform subdomain as the fallback host for those contexts.
  • Your site forwards the wrong host (or none). Make sure your integration forwards the visitor's host as X-Forwarded-Host. If it forwards an empty value, Steeren falls back to its own host and resolves the wrong site or none at all. Using @nukipa/site-sdk handles this for you.
  • A multi-label subdomain like blog.acme.nukipa.io won't resolve. Only single-label subdomains resolve. Use one label, or put your blog on a verified custom domain.

[!NOTE] NUKIPA_TENANT_HOST is a fallback, not an override. When a real custom domain is live, the visitor's actual domain has to win so Steeren can hand back that domain's Google Search Console verification token. If you force NUKIPA_TENANT_HOST to your platform subdomain on every request, Search Console verification stalls at "verification token could not be found." Point NUKIPA_TENANT_HOST at your platform subdomain and leave it as the fallback only.

Why you should always call through the SDK

If you're integrating your own site, go through @nukipa/site-sdk (getNukipaClient() / getMiddlewareClient(req)) rather than hand-rolling fetch calls to the public API. The SDK normalizes the headers the platform needs - the visitor host for resolving your site, the visitor IP for analytics, and the user agent so real browsers are counted as such.

The catch that bites people: public reads and writes don't reject a malformed call with an error. They self-resolve from the request, so a hand-built call that omits these headers won't fail loudly - it silently resolves to the wrong site (or none) and quietly drops the data. That stays invisible until you notice missing visits or leads that never arrived. The SDK is the supported path; use it.

[!TIP] Some serverless runtimes strip the forwarded-IP header on outbound calls. The SDK works around this so your Visitors count keeps working; a raw fetch reimplementation loses it and the dashboard shows "-" for visitors. Another reason to use the SDK.

Rate limits

Under heavy load you may hit a rate limit. A few things worth knowing:

  • Reads are not rate-limited. Viewing posts, folders, and other public content is unlimited.
  • Submits (forms, newsletter signups, audit runs) share a generous limit. It's deliberately high and shared, so normal traffic won't trip it.

Symptom -> what to do:

  • Form submits return a "too many requests" error under heavy load. You've hit the shared submit limit. The limit is raisable without a redeploy via the PUBLIC_SUBMIT_RATE_LIMIT environment variable - bump it if your traffic legitimately needs more headroom. If you need to single out abuse from one source, do that at your CDN/edge (Cloudflare, Vercel WAF); the platform limit isn't a per-visitor anti-abuse tool.
  • Visits go missing during a traffic spike, with no visible error. Visit tracking is intentionally fire-and-forget - if a tracking call is throttled, it's dropped silently so it never breaks a page load for the visitor. The result is gaps in analytics during the spike, not errors anyone sees.

Forms not reaching your CRM

First, the reassuring part: the submission is always saved. Even if the CRM hand-off lags or fails, the lead is captured - check your submissions inbox in the dashboard. The two form types just report their CRM status differently.

  • Lead forms save the submission and create the CRM contact in the background. They don't flip a visible "synced" status - the way to confirm a lead reached the CRM is that a contact now exists for it, not a status badge on the submission.
  • Inline contact forms (the ones embedded in a post) do show a status: synced, failed, or flagged as spam.

Symptom -> cause -> what to do:

  • A lead-form submission is in my inbox but doesn't look "synced". Expected - lead forms don't show a sync status. Confirm the matching contact in your CRM. If it's not there, the CRM hand-off didn't complete (e.g. the CRM was briefly unavailable); the submission is intact and can be re-processed.
  • An inline contact-form submission never reached the CRM. Check its status. "Failed" means the hand-off to the CRM didn't go through. "Spam" means it was classified as a bot and intentionally never forwarded.
  • A real visitor's submission got marked as spam. A hidden anti-bot field was filled in (some browser autofill extensions do this), or every field had identical text. Spam submissions still show the visitor a success message on purpose, so a bot can't tell it was caught. You can change the status back to received from your submissions inbox and process it normally.
  • New leads arrive with no owner assigned. Expected - leads captured from a public form come in unowned. Assign an owner in your CRM.

If you're integrating your own site, the form has to post through the same-origin relay your SDK sets up, so the request carries the visitor's host. A form stuck on "loading" or never landing is usually a sign the relay isn't wired - route the submit through the SDK rather than calling the public API directly.

[!NOTE] Gated posts unlock by email. When a visitor submits a gate form, Steeren unlocks the full post on their next page view by matching their email. On a Steeren-managed site this is automatic. If you run your own site, you own visitor identity: persist the visitor's email after they submit and forward it as X-Visitor-Email, or they'll hit the gate again on every page even though their lead saved fine. The lead is captured either way; remembering the visitor so the post unlocks is your site's job.

Lead scoring (fit/intent) runs in the background after a lead is created. If scores are missing for a while, the scoring job is still catching up - it's not part of the synchronous submit.

Sends and sequences stuck

Newsletters and nurturing sequences are sent by background workers that pick up due work on a short interval. If something is stuck, it's almost always one of the cases below.

Symptom -> cause -> what to do:

  • A scheduled newsletter never sends and stays "scheduled". The background job system couldn't be reached, so the due issue was never picked up. Confirm the sending service is configured and running (SERVICE_JOBS_URL must be set if you self-host the platform), then reschedule.
  • A "send now" issue is stuck on "sending" and nothing went out. Same root cause - the job system was unavailable when you hit send. Fix the jobs configuration; this state doesn't self-recover, so re-trigger the send once it's healthy.
  • A send job that started just stopped partway. A worker that goes silent for several minutes is automatically marked failed (rather than hanging forever), so you can safely re-trigger it. No need to wait it out.
  • A nurturing step doesn't fire when I expect. A step's send time is computed from its position and delay. If you edited the step, its scheduled time was recomputed - give it until that new time passes.
  • I tried to unschedule an issue and got a conflict / "can't unschedule". You can only pull back an issue while it's still "scheduled". Once it has flipped to "sending", it's too late to unschedule.

You don't have to worry about duplicate sends - the system guards against sending the same step or newsletter to the same person twice, even if a job retries.

[!WARNING] Moving a contact to a closed state (customer, disqualified, unqualified, opted-out) or having them unsubscribe cancels every in-flight nurturing sequence for that contact, across all sequences. If a sequence "stopped on its own", check whether the contact's stage or status changed - that's usually the cause, and it's intended.

Deploys stuck (self-hosting your own site)

A site deploy reconciles your hosting project against your connected GitHub repo, sets environment variables, attaches the domain, and triggers a production build. Re-running a deploy is always safe.

Symptom -> cause -> what to do:

  • I pushed to my repo but the deploy never starts. Commits that already exist on the branch don't always auto-build when the project is first linked. Re-run the deploy from Steeren - it explicitly triggers a fresh build.
  • The deploy fails with "project is not linked to GitHub repo ...". Your host can't see the repo. Install your hosting provider's GitHub App on the organization that owns the repo, grant it access to that specific repo, then re-run. The error message points at the exact repo it couldn't see.
  • After I changed which repo is connected, the deploy still builds the old one. Re-run the deploy so it re-links to the new repo, then redeploy.
  • I changed NUKIPA_TENANT_HOST or NUKIPA_GATEWAY_URL in my hosting project but the site still uses the old value. The deployer only sets these variables if they don't already exist - it won't overwrite a value you set by hand. That means your manual value sticks (good), but the deployer also won't "fix" a stale one for you. Update the variable directly in your hosting project and redeploy.

[!NOTE] When a deploy fails, the error Steeren shows is a generic pointer to your hosting provider's build log. For a build that compiles locally but fails when deployed, the real error is in your hosting dashboard's build output, not in the Steeren deploy status.

"Verified human" visitor count (self-hosting your own site)

Steeren can count verified human visits using a lightweight, cookieless check that confirms a real browser rendered the page (it doesn't track or fingerprint anyone). On a Steeren-managed site this is built in. On a custom Next.js site it is not wired up by default - without it, you won't get a confirmed-human count.

If you want it on a custom Next site, @nukipa/site-sdk ships a helper, nukipaBeaconScript({ nonce, endpoint }), that builds the inline script for you. You generate the per-pageview value and add the script yourself.

Two things in the starter's layout are platform contracts - don't remove them:

  1. The Google Search Console verification tag - removing it stalls Search Console verification indefinitely.
  2. <NukipaFeedback /> in the page body - the design-review feedback loop depends on it.

[!WARNING] "Cookieless" describes that verified-human check (and the strictly-functional session that keeps every page view from looking like a brand-new visit). It does not cover your whole site. The moment you add a non-essential cookie - analytics, ads, a third-party tracker - your site moves into cookie-consent (ePrivacy/GDPR) scope, and that's on you.

FAQ

A post's body just stops mid-paragraph with no form. Is it broken? No - the post is gated, and your site isn't rendering the gate form. A Steeren-managed site shows the form automatically. The visitor unlocks the rest by submitting it; Steeren remembers them by email on their next page view. (If you run your own site, see the gating note above - you have to forward the visitor's email.)

A lead synced to my CRM, but the submission doesn't show as "synced". Bug? No. Lead forms don't display a sync status - only inline contact forms do. Confirm the contact exists in your CRM to verify it synced.

My form submit hit a rate limit, but only sometimes. Is it my form? It's the shared submit limit under load, not a per-form cap. If your traffic legitimately needs more, raise PUBLIC_SUBMIT_RATE_LIMIT (no redeploy needed).

My visits aren't being recorded. Most often the visitor host isn't reaching Steeren - your site forwarded an empty host and the visit was dropped or attributed wrong. Make sure your integration reads the request's host (x-forwarded-host / host) and set NUKIPA_TENANT_HOST as the build/edge fallback. Using @nukipa/site-sdk handles this.

A background job is stuck "running". Will it ever resolve? Yes. A job whose worker goes silent for several minutes is automatically marked failed rather than hanging forever - so you can re-trigger it.

My edits aren't showing on the live site. Edits don't go live until you republish the post. Publish again and the changes appear. (And note: unpublishing a post makes its URL return "not found" right away.)

Served live from the platform · /docs/troubleshooting-and-gotchas