Skip to content

Troubleshooting

Find your symptom below. Commands with docker compose are run on the Looku server in the deploy folder.

Most answers start here. The last 50 lines of the receiver’s log:

Terminal window
docker compose logs --tail 50 ingest

Use dashboard, tunnel or caddy instead of ingest for the other containers. docker compose ps shows whether each container is running (Up) and healthy.

Go through these in order. The first one that fails is usually the cause.

  1. Is the site running a production build with the settings? The connector sends nothing from npm run dev, from Vercel preview deployments, or when NODE_ENV is not production. On Vercel, settings apply only after a redeploy.

  2. Is your own browser sending Do Not Track or Global Privacy Control? Brave, and Firefox with some settings, send it by default, and Looku then skips you on purpose. Test with another browser or your phone.

  3. Does the receiver answer? From a terminal on any computer (on Windows, in PowerShell with curl.exe):

    Terminal window
    curl -s -o /dev/null -w "%{http_code}\n" -X POST https://looku.example.com/ingest

    401 is correct: the receiver answered. 403 means a firewall rule blocks it (check the Cloudflare rule). 000, 502 or 530: the address does not reach the receiver; see the sections below.

  4. Are the three settings right? Send one test page view with your site’s settings. In your site’s folder (the one with lib/looku.js), create a file called looku-test.mjs with this content, and replace the three values with your site’s settings:

    import { sendToLooku } from "./lib/looku.js";
    const settings = {
    endpoint: "https://looku.example.com",
    siteId: "myblog",
    signingKey: "yourkey",
    };
    const pageview = {
    type: "pageview",
    ts: new Date().toISOString(),
    path: "/looku-test",
    ip: "203.0.113.1",
    ua: "Mozilla/5.0 (X11; Linux x86_64) Firefox/140.0",
    };
    console.log(await sendToLooku(pageview, settings));

    Run it in the same folder (the same command on Windows, macOS and Linux):

    Terminal window
    node looku-test.mjs

    Node may first print a warning about a module type (MODULE_TYPELESS_PACKAGE_JSON); it is harmless, so do not change package.json because of it. Delete looku-test.mjs afterwards, because it contains your signing key. true means Looku accepted it: a page view of /looku-test appears in the dashboard, and the problem is in how the site gets its settings. false with step 3 answering 401 means the site id or key is wrong: check for extra spaces, or make a new key with site:rotate-key. The test also fails if the clock of the computer is more than five minutes off.

  5. Is the page excluded? API routes, files with a dot in the name, prefetches, bots and paths in excludePaths are not counted. Requests without Accept-Language, with a tool’s user agent such as curl’s, or (over HTTPS) with a modern browser’s user agent but no Sec-Fetch-Mode header count as bots.

    Testing quickly? A visitor who loads more than 4 pages in three seconds, or more than 20 in two minutes, is taken for a crawler: that day’s page views of the visitor are removed and later ones are skipped, with no error. Click at a normal pace, and test again with another browser or on the next day.

  6. Is the dashboard showing the right site and dates? Choose the site and today in the dashboard.

The address in your browser is not in LOOKU_API_HOSTS. Add it exactly as you type it, with the port, for example 192.168.1.10:8788 or looku.example.com. Separate several with commas. Then docker compose up -d dashboard.

LOOKU_API_ALLOW is set and your address is not in it. Your home’s public address may have changed (see the VPS guide). Behind a proxy, LOOKU_TRUST_PROXY must be the number of proxies; with a wrong number every visitor looks the same or empty, and everyone gets Forbidden. After a change, docker compose up -d dashboard.

Dashboard does not open at all (home server)

Section titled “Dashboard does not open at all (home server)”
  • docker compose ps: is looku-dashboard-1 Up?
  • Is LOOKU_DASHBOARD_BIND the server’s address on the network you are on? 127.0.0.1 opens only on the server itself.
  • Is your device on the home network (or Tailscale)? On mobile data the address does not open, by design.

“Wrong password” or “Too many failed logins”

Section titled ““Wrong password” or “Too many failed logins””

After 10 failed logins from one address in 15 minutes, logins from that address are refused for the rest of the 15 minutes. Wait, then try again. If you have forgotten the password, set a new one on the server:

Terminal window
docker compose run --rm -it ingest admin:password

The key is shown only once. Make a new one; the old one stops working at once, so update your site’s settings right after:

Terminal window
docker compose run --rm ingest site:rotate-key myblog

The tunnel cannot reach the receiver.

  • docker compose --profile tunnel ps: is looku-tunnel-1 Up? If it is missing, start it with docker compose --profile tunnel up -d.
  • In Cloudflare, the route’s Service URL must be http://ingest:8787. localhost does not work, because inside the tunnel container localhost is the container itself.
  • docker compose logs --tail 50 tunnel shows whether the token was accepted.

docker compose logs --tail 50 caddy shows the reason. Usually:

  • the DNS record does not point to the server yet (nslookup looku.example.com),
  • port 80 or 443 is closed in the provider’s firewall or ufw,
  • the record is behind Cloudflare’s orange cloud (use DNS only).

The receiver’s log says the database cannot be opened. The data folder must belong to user 1000:

Terminal window
sudo chown -R 1000:1000 data
docker compose up -d

Each site has its own time zone, set with site:add --timezone (default Europe/Helsinki). The nightly job and the monthly email use LOOKU_TIMEZONE. Check docker compose run --rm ingest site:list, and change a site’s time zone with docker compose run --rm ingest site:timezone myblog Europe/Helsinki. Days already recorded keep their dates; the new time zone applies to new page views.

Looku recognises a visitor for one day only. A person who visits on three days counts as three visitors in a month, and the same person on a phone and a laptop counts twice. This is the price of not storing identifiers. Compare page views, which are counted the same way everywhere.

  • npm error engine or Unsupported engine: Node.js is too old; install version 22 or newer.
  • gyp ERR!: the SQLite library has to be built; install build tools (sudo apt install python3 make g++) and run npm install again.

About the author