Skip to content

Troubleshooting & debugging

When something misbehaves, work in this order: turn on logging → listen for error → match the symptom below.

1. Turn on logging

The client is silent by default — it emits diagnostics only through a logger you pass. Attach the built-in ConsoleLogger to send verbose logs to the console across every channel (login, secure MQTT, P2P, push, live media), each line prefixed by subsystem ([mega] / [smqtt] / [p2p] / [push] / [fcm] / [live]):

ts
import { EufyMega, ConsoleLogger } from "eufy-mega";

const eufy = new EufyMega({ email, password, region: "eu", logger: new ConsoleLogger() });
// or gate by severity — warnings and errors only:
const quiet = new EufyMega({ email, password, region: "eu", logger: new ConsoleLogger("warn") });

Any logger with debug / info / warn / error methods works too (tslog and winston fit directly; pino via a one-line adapter) — see Getting started.

2. Listen for error

The realtime channels are independent — one channel's failure surfaces on the facade's catch-all error event without aborting the others. Always attach a handler; an unhandled error on an EventEmitter throws.

ts
eufy.on("error", (err) => console.error("[eufy]", err));

Media streams have their own error (including a start stall — see below) and a stop:

ts
const stream = await cam?.live();
stream?.on("error", (err) => console.error("stream", err));
stream?.on("stop", () => console.log("source ended — re-attach to rebuild"));

3. Common symptoms

Symptom / errorLikely causeWhat to do
login() firsta method was called before authentication finishedawait eufy.login() and step through captcha/2FA until ok, then continue
no pending captcha — call login() firstsolveCaptcha() called without an active challengedrive the login() result: only call solveCaptcha when status === "captcha"
Captcha keeps appearing / logins briefly blockedrepeated failed-password logins on one device fingerprint trip an abuse cooldowngive the client its own distinct phoneModel / openudid, then back off before retrying (see Getting started)
2FA prompt on every runthe device fingerprint changed, so it looks like a new devicekeep openudid stable and use a store so the session persists
dev.camera is not a function (or any other capability)a device carries only the accessors for capabilities it has, so the accessor is absent — not a function returning undefined. A capability the device hadn't yet reported evidence for is added when it does (deviceCapabilities)call it optionally: dev.camera?.()?.on(). Branch on dev.has("camera") or read dev.capabilities to decide what a device can do; the presence of an accessor is not a check you should write yourself
A write method is missing from dev.<cap>() (e.g. no siren().on())that write isn't confirmed on a mega device yet, so it's absent rather than present-and-throwing (currently siren, a few lock settings)expected — a method being present means its wire is verified; the read getter still works. (The untyped setProperty escape hatch still throws "wire unverified" for such a write.)
A command fails only on a standalone camerasome controls need a HomeBase-attached device and aren't available standaloneexpected — drive that control on a HomeBase-attached device, or use the property that adapts automatically
live stream failed to start (no frames within warm-up window)the source never produced a frame in timehandle the stream error, then call cam.live() again to rebuild
timeout waiting for a clean keyframea snapshot/record couldn't get a keyframe in the windowretry, or widen the timeout via the call's options
ffmpeg not runnable / snapshot or record failsffmpeg isn't on PATH (needed for JPEG snapshot / mp4 record / WebRTC container)install ffmpeg, or use the ffmpeg-free paths (openReadable(), recordFragments()); see §5
p2p down / smqtt reconnecting on errora transient transport dropthe channels reconnect on their own; re-attach live streams when a consumer gets stop

4. Streams that hang or stop

  • No silent hang. live() keeps nudging the start until the first frame arrives; if none comes in the warm-up window it emits error rather than hanging. Handle error.
  • Reconnect. On a dropped session the source stops and consumers get stop / error. Call cam.live() again to rebuild the pull. See Consuming a live stream for the full lifecycle (one pull / many consumers, keyframe priming, power budgets).
  • Trace the lifecycle. With a logger attached (§1), [live …] lines trace a stream warming, going live, a warm-up timeout, an upstream drop, and the linger-before-teardown — the detail you want when a live view won't start or drops unexpectedly.

5. Media (snapshot / record / ffmpeg)

The JPEG snapshot (snapshotLive), one-shot record, and WebRTC-container paths shell out to ffmpeg. When one of them fails, surface ffmpeg's own diagnostics through your logger: raise ffmpegLogLevel on the client and the SDK forwards ffmpeg's stderr as [ffmpeg]-prefixed debug lines.

ts
const eufy = new EufyMega({ email, password, ffmpegLogLevel: "trace", logger: new ConsoleLogger("debug") });

Accepted values (quiet → loud): quiet panic fatal error (default) warning info verbosedebug trace. An unset/invalid value stays at error. (createWebRtcPeer takes the same ffmpegLogLevel option for its own container mux.)

This is ffmpeg's own verbosity — orthogonal to the Logger's min-level, which still gates whether the [ffmpeg] lines are shown. So to see them you need both: a level above error and a logger that shows debug (e.g. new ConsoleLogger("debug")).

Note the ffmpeg-free egress paths don't need any of this: openReadable() (raw Annex-B bytes) and recordFragments() (fMP4 / CMAF) mux without ffmpeg on PATH.

6. Login & session issues

Captcha and 2FA are expected flow, not errorslogin() returns a status to switch on, it does not throw. Rapid or repeated failed logins can trigger a captcha or a short cooldown even for valid credentials. Full flow and persistence rules are in Getting started.

Still stuck?

Re-run with new ConsoleLogger("debug"), capture the error output, and check the behavior against the API reference for the method you're calling — signatures and the events each one emits are documented there.

Independent and unofficial. Not affiliated with, endorsed by, or sponsored by Anker Innovations or eufy. "eufy" and "Anker" are trademarks of their respective owners. Use responsibly — rapid or failed logins can trigger captcha or temporary cooldowns.