MainSDK
Search⌘K
Interfaces

Messaging and notifications

Feedback and support

feedback

Let users report a problem or open a ticket, with the trace, version and steps attached and screenshots redacted.

Building for 0.6ships as a beta APIPhase 2 · Cloud and Teams, 1.0Spec debug-loopFree in your app, Apache-2.0

Status Status is where the work is: Planned (in a milestone, not started), Building (tickets in progress), Preview (usable, may change), then the stability it ships at.

Stability The promise an interface ships with.

  • Stable Follows semantic versioning; breaking changes need a new major, 12 months of overlap and a codemod.
  • Beta Usable in production; may change before it becomes stable.
  • Experimental May change or go away; needs an explicit opt-in in main.yaml.
Stability levels
Updated 2026-10-28

Let your users report a problem or open a ticket. Each report arrives with the trace, version, device and steps, a redacted screenshot, and its matching error. Use it for a report button.

At a glance

feedback:
  tracker: linear
  prompt: { onCrash: true, onFailedAction: true }

Calls

  • feedback.open({ category? })
  • feedback.onCrash({ code? })
  • feedback.onFailedAction({ code })
  • support.ticket({ subject, body })

Guarantees

Whatever the driver.

  • Screenshots redacted
  • Support access audited

Drivers

4 drivers. Select one to see its line in main.yaml.

main.yamlBuilt in (default)
feedback:
  driver: builtin

Change this one line to swap providers; your calls stay the same.Built-in and local drivers integration

Codes

No check or runtime codes are assigned to this interface yet.

Features

Nothing here has shipped yet. Each feature lands in its phase; the spec ticket builds it.

FeaturePhaseMilestoneSpec ticket
Report capture with trace, version and stepsPhase 20.6debug-loop#feedback-capture
Support ticketsPhase 20.6Not specified yet

MainSDK Cloud

Everything above is free in your app. Cloud adds these on top, by plan:

PlanWhat it adds
TeamsInbox history and triage of reports

Quick start

main.yaml
feedback:
  tracker: linear
  prompt: { onCrash: true, onFailedAction: true }
app/feedback.ts
import { createFeedback, StepRecorder } from "mainsdk/feedback";

// Stand-ins for what your host app provides.
declare const currentTrace: () => string | undefined;
declare const showReportForm: (o: { reason: string }) => Promise<{ text: string } | undefined>;
declare const getqr: { upload: (bytes: Uint8Array, o: { name: string; type: string }) => Promise<{ url: string }> };
declare const cloud: { post: (path: string, body: unknown) => Promise<void> };

export const steps = new StepRecorder();

export const { feedback, support } = createFeedback({
  version: "3.1.0",
  device: () => ({ platform: "ios", os: "19.1" }),
  steps,
  trace: () => currentTrace(),
  ask: (o) => showReportForm(o),            // returns { text, screenshot? } or undefined
  upload: (bytes, o) => getqr.upload(bytes, o), // a getqr.id upload; returns { url }
  send: (report) => cloud.post("/v1/feedback", report),
  prompt: { onCrash: true, onFailedAction: true },
});

Configuration

main.yaml
feedback:
  tracker: linear                # linear | jira | zendesk | plain
  prompt: { onCrash: true, onFailedAction: true }

What you get

CallWhat it does
feedback.open({ category? })Shows the report form and sends the report.
feedback.onCrash({ code? })Asks after a crash, only when prompt.onCrash is on.
feedback.onFailedAction({ code })Asks after a failed action, only when prompt.onFailedAction is on.
support.ticket({ subject, body })Sends a ticket with the same trace, version and steps.

Each call returns the report id, or undefined when the customer closed the form or anything failed. A failure never reaches your app (ADR-0003).

Examples

What a report carries

A report holds the trace, the app version, the device, the last steps and, when there is one, a screenshot. Text is redacted for emails, bearer tokens and key formats. Note each step with steps.note("opened checkout"); never put a value from user data in a step.

A screenshot with its text fields blacked out

Give the screenshot as RGBA pixels with the boxes of its text fields. They are filled black before the image is uploaded, and only the redacted image ever leaves the device. The Cloud accepts only a getqr.id link as the screenshot.

ts
import { maskScreenshot } from "mainsdk/feedback";

const width = 2;
const height = 2;
const rgba = new Uint8Array(width * height * 4);

const safe = maskScreenshot({ width, height, rgba, fields: [{ x: 40, y: 120, w: 280, h: 44 }] });

Read the inbox

The console inbox groups each report with the error it matches, by trace first and then by error code, so one error and the customers who hit it sit together. Free keeps the free history window; Teams keeps it all and can forward a report to your tracker.

Reply to the reporter

Replies go back to the customer through notify.

lib/reply.ts
import { notify } from "mainsdk";

export async function replyToReport(user: { id: string }, reportId: string) {
  await notify(user, { template: "feedback.reply", data: { reportId }, category: "support" });
}

Errors and checks

CodeWhenFix
MAIN-DEBUG-0007The Cloud refused a report: a field is missing, or the screenshot is not a getqr.id uploadSend id, text, version, device and steps, and upload the screenshot through getqr.id
MAIN-DEBUG-0001Forwarding a report to a tracker needs TeamsMove the project to Teams

Swapping drivers

main.yaml
feedback:
  tracker: zendesk   # was linear

Your feedback.open() and support.ticket() calls stay the same. Past tickets stay in the old tool.

Testing

createFeedback takes every port as an argument, so a test passes a fake ask, upload and send and reads what was sent. See Debug your app and Test your app.

Security and privacy

  • Screenshots are redacted before they leave the device.
  • Support access to a user's data is audited.
  • Reports carry the trace, so you see what failed without asking the user for details.

What Cloud adds

Capturing reports is free. Teams adds inbox history and triage of reports. See Free in-app and Cloud.

FAQ

Can reports land in my issue tracker? Teams can forward a report to Linear, Jira, Zendesk or Plain through a forwarder your host supplies.

Why a screenshot link and not the image? Screenshots are uploaded through getqr.id and the Cloud stores only the link (ADR-0009). See Debugging.

Next

Was this page helpful?

↑↓ moveEnter openEsc close

Not decided yet