> ## Documentation Index
> Fetch the complete documentation index at: https://docs.overlayed.gg/llms.txt
> Use this file to discover all available pages before exploring further.

# Bug Report Logs

> Receive user logs submitted through bug reports.

A user hits a bug mid-match and all you get is "the overlay stopped working" - with no logs, that report is
undebuggable. This guide builds a bug report flow end to end: the user fills out a short form in your overlay, and your
code submits their description together with their log files to your Overlayed dashboard, where you can download and
read them.

<Info>
  This guide covers the bug report workflow specifically. For the full API reference, see [User
  Feedback](/logging/user-feedback) and [How Logging Works](/logging/introduction).
</Info>

## How Bug Report Logs Work

Before writing any code, it helps to know four things about how Overlayed handles feedback and logs:

1. **File logging is automatic.** Every message sent through `overlay.log` is written to a log file in your
   application's log directory. One file is created per day, and files are deleted after 7 days. You don't manage
   these files - they're what gets shipped with a bug report.
2. **`submitFeedback` does the collection for you.** One call zips your app's log files, Overlayed's own recent log
   files, and any extra files you attach, then uploads the bundle with the user's message. There is no server for you
   to build - submissions land in the [Overlayed Dashboard](https://overlay.dev/feedback/bug-reports).
3. **It's a main-process API.** The report form lives in a renderer window, but `overlay.log.submitFeedback` runs in
   the Electron main process. The form hands its data to the main process over standard Electron IPC.
4. **The user reports; your code submits.** End users only type a message and click a button - calling the API, and
   deciding what context rides along with it, is your code's job.

## Building the Bug Report Flow

<Steps>
  <Step title="Log things worth reading">
    A bug report is only as useful as the logs inside it. Log state transitions and failures as they happen, using
    scoped loggers so every line is prefixed with where it came from:

    ```typescript main.ts theme={null}
    const matchLog = overlay.log.scope("match");

    matchLog.info("Match started");
    matchLog.error("Failed to parse round event", { raw: event });
    ```

    The top-level `overlay.log.info` / `warn` / `error` methods take a single message string; scoped loggers accept
    any number of arguments, so use a scope when you want to attach data to a line.

    <Tip>
      `debug` calls are dropped entirely unless [debug mode](/logging/debug-mode) is enabled - they won't appear
      in log files from production users. Log anything you'll need for diagnosing real-world reports at `info`
      or above.
    </Tip>
  </Step>

  <Step title="Create the report window">
    Create a window to host your report form, with a preload script for the IPC bridge:

    ```typescript main.ts theme={null}
    import path from "node:path";

    const reportWindow = overlay.windows.createWindow({
    	width: 420,
    	height: 360,
    	show: false,
    	webPreferences: {
    		preload: path.join(__dirname, "preload.js"),
    	},
    });
    ```

    See [Creating Windows](/windows/introduction) for out-of-game vs. in-game windows - a report form works as
    either.
  </Step>

  <Step title="Bridge the form to the main process">
    In the window's preload script, expose a function the form can call:

    ```typescript preload.ts theme={null}
    import { contextBridge, ipcRenderer } from "electron";

    contextBridge.exposeInMainWorld("bugReports", {
    	submit: (report: { email?: string; message: string }) => ipcRenderer.invoke("bug-report:submit", report),
    });
    ```

    Your form UI then calls `window.bugReports.submit({ email, message })` when the user clicks send.
  </Step>

  <Step title="Submit the feedback">
    In the main process, handle the IPC call by passing the user's input to `submitFeedback`:

    ```typescript main.ts theme={null}
    import { ipcMain } from "electron";

    ipcMain.handle("bug-report:submit", async (_event, report: { email?: string; message: string }) => {
    	const feedbackId = await overlay.log.submitFeedback("bug_report", {
    		email: report.email,
    		message: report.message,
    	});

    	return feedbackId !== undefined;
    });
    ```

    The call resolves to a feedback ID on success, or `undefined` if the upload failed. There is no automatic
    retry, so use the return value to show a success or error state in your form.
  </Step>

  <Step title="Read the report in your dashboard">
    Open [overlay.dev/feedback/bug-reports](https://overlay.dev/feedback/bug-reports). Each submission includes the
    email, username, and message the user provided, plus a zip containing your app's log files and Overlayed's
    internal logs from the last 7 days.
  </Step>
</Steps>

## User-Driven vs. Event-Triggered Reports

`submitFeedback` doesn't have to wait for a user to fill out a form - you can also fire it from code when something
goes badly wrong.

<Tabs>
  <Tab title="User-driven report">
    The flow above. The user describes the problem in their own words, and your code forwards it. The same form can
    double as a feature-request box - submit with type `"suggestion"` instead of `"bug_report"`:

    ```typescript theme={null}
    await overlay.log.submitFeedback("suggestion", {
    	email: report.email,
    	message: report.message,
    });
    ```

    Both types travel through the same pipeline and include the same log zip; the type controls how the submission
    is categorized in your dashboard.
  </Tab>

  <Tab title="Event-triggered report">
    When your code catches an error it can't recover from, submit a report directly - the logs captured up to that
    moment are exactly what you'll need:

    ```typescript theme={null}
    const settingsLog = overlay.log.scope("settings");

    try {
    	await loadUserSettings();
    } catch (error) {
    	settingsLog.error("Failed to load user settings", error);

    	await overlay.log.submitFeedback("bug_report", {
    		message: "Event-triggered report: failed to load user settings",
    	});
    }
    ```

    All feedback fields are optional, so an event-triggered report doesn't need an email or username.

    <Warning>
      Guard event-triggered submissions - an error that fires on every game tick would submit a report (and upload a
      log zip) on every occurrence. Track a "already reported this session" flag per failure type.
    </Warning>
  </Tab>
</Tabs>

## Attaching Your Own Context

Logs tell you what happened over time; sometimes you also want a snapshot of *right now*. `submitFeedback` gives you
two places to put it:

* **`extra`** - a record of structured data stored on the feedback entry itself. Good for small values you want to see
  at a glance.
* **`additionalFiles`** - named files added inside the log zip. Good for larger payloads like a serialized match
  state.

```typescript main.ts theme={null}
await overlay.log.submitFeedback(
	"bug_report",
	{
		message: report.message,
		extra: {
			inGame: overlay.hasAnyActiveGames(),
		},
	},
	{
		additionalFiles: {
			"matchState.json": JSON.stringify(currentMatchState),
		},
	},
);
```

<Warning>
  Everything is uploaded as-is - log lines, `extra` values, and additional files are not sanitized. Don't log
  secrets, tokens, or personal data you wouldn't want attached to a bug report.
</Warning>

## Sending Logs Somewhere Else

If you want the same log bundle in your own pipeline - your support system, your own storage - `getLogsZip` returns
the identical zip (a [JSZip](https://stuk.github.io/jszip/) instance) without submitting anything:

```typescript theme={null}
const zip = overlay.log.getLogsZip({
	additionalFiles: {
		"matchState.json": JSON.stringify(currentMatchState),
	},
});

const zipBase64 = await zip.generateAsync({ type: "base64" });
await sendToMyServer(zipBase64);
```

<Tip>
  Building the zip writes its own progress lines ("Zipping: ...") into the log. Pass `{ silent: true }` in the
  options to suppress them.
</Tip>

## FAQ

<AccordionGroup>
  <Accordion title="What happens if the upload fails or the user is offline?">
    `submitFeedback` resolves to `undefined` and the failure is written to the log - it does not throw for a failed
    request, and it does not queue or retry the submission. Check the return value and show an error state so the
    user can try again later.
  </Accordion>

  <Accordion title="How far back do the submitted logs go?">
    Up to 7 days. Log files are created per day and automatically deleted after 7 days, so the zip contains at most
    a week of your app's logs, plus Overlayed's own log files from the same window.
  </Accordion>

  <Accordion title="Does console.log output end up in bug reports?">
    No. Only messages sent through the logging module (`overlay.log` and its scopes) are written to the log files
    that get zipped. If you want it in bug reports, log it through `overlay.log`.
  </Accordion>

  <Accordion title="Will debug logs appear in reports from production users?">
    Only if you shipped with debug mode enabled. When debug mode is off, `debug` calls are dropped entirely - not
    written to the console or the file. See [Debug Mode](/logging/debug-mode).
  </Accordion>

  <Accordion title="Are game crash dumps included in bug reports?">
    No - crash dumps are a separate flow. When a monitored game closes, Overlayed scans for new dump files and
    emits a `new` event on `overlay.crashDumps`; you submit those with `overlay.crashDumps.submit(id)`. See [Crash
    Dumps](/logging/crash-dumps).
  </Accordion>

  <Accordion title="Can I tell which user or version a report came from?">
    Partially, automatically. Every submission carries an anonymous per-install user identifier and, when
    available, the release ID of the running build - so you can group reports by install and by version without
    doing anything. For a real identity, collect `email` or `username` in your form (both are optional), or put
    your own account ID in `extra`.
  </Accordion>

  <Accordion title="Do I need my own backend to receive reports?">
    No. `submitFeedback` uploads directly to Overlayed, and you read submissions in the
    [dashboard](https://overlay.dev/feedback/bug-reports). Only reach for `getLogsZip` if you additionally want the
    logs in your own systems.
  </Accordion>

  <Accordion title="Can I test the flow during development?">
    Yes - `submitFeedback` works in development too. Submit a test report and check your dashboard's feedback page
    for the entry and its attached zip.
  </Accordion>
</AccordionGroup>

## Next Steps

<CardGroup cols={2}>
  <Card title="User Feedback Reference" icon="message-exclamation" href="/logging/user-feedback">
    The full `submitFeedback` and `getLogsZip` API, including all feedback fields.
  </Card>

  <Card title="How Logging Works" icon="file-lines" href="/logging/introduction">
    Log levels, file output, and where log files live on disk.
  </Card>

  <Card title="Crash Dumps" icon="bomb" href="/logging/crash-dumps">
    Detect game crashes and let users submit the dump files.
  </Card>

  <Card title="Debug Mode" icon="bug" href="/logging/debug-mode">
    Enable verbose logging during development and troubleshooting.
  </Card>
</CardGroup>
