Skip to content
AppNorth
Log in

iOS SDK

Private feedback

Use createFeedback for a private problem report, suggestion, or comment. This is separate from public community ideas and the support chat conversation. Your app supplies the form and explicit consent for any diagnostics or capture.

View Markdown

Submit a report

Supply a stable HTTP(S) URL representing the screen, a positive viewport size, and the user's message. pageURL is report context, not a custom-scheme deep link. Keep credentials and personal data out of that URL.

PrivateReport.swift
import Foundation
import AppNorth

func submitReport(
    client: AppNorthClient,
    message: String,
    screenURL: URL,
    viewport: AppNorthViewport,
    retryKey: String
) async throws -> AppNorthFeedbackReceipt {
    let report = AppNorthCreateFeedback(
        type: .problem,
        message: message,
        pageURL: screenURL,
        pageTitle: "Settings",
        locale: Locale.current.identifier,
        viewport: viewport
    )
    return try await client.createFeedback(report, idempotencyKey: retryKey)
}

Use the current screen's dimensions for viewport. Messages must contain 3–5,000 characters after trimming. The receipt contains id, correlationId, screenshotStored, and deduplicated; check screenshotStored instead of assuming the attachment was retained. Reuse the key and unchanged payload only for retries of the same report.

Attach context deliberately

AppNorthDeviceContext accepts app name/version/build, model/type, and OS/version. It flattens whitespace and limits each string to 120 Swift characters; it does not remove arbitrary secrets. The host chooses and sanitizes the values.

Diagnostics use AppNorthFeedbackDiagnostic with a category, optional level, message, timestamp, and JSON metadata. The server accepts at most 100 diagnostics and 1,000 characters per diagnostic message. Never forward raw authorization headers, cookies, passwords, tokens, or signing keys.

Capture only after consent

Implement the capture and redaction protocols in your app, then call the helper. The SDK contains no automatic screenshot collector or consent UI.

ConsentedCapture.swift
import AppNorth

func reportScreenshot(
    consent: Bool,
    capture: any AppNorthScreenshotCapturing,
    redactor: any AppNorthScreenshotRedacting
) async -> String? {
    await captureAppNorthScreenshot(
        consent: consent,
        adapter: capture,
        redactor: redactor
    )
}

The helper returns nil if consent, either adapter, validation, or redaction fails. It also rejects unchanged redactor output. Valid output is a PNG, JPEG, or WebP base64 data URL of at most 2,800,000 UTF-8 bytes. A changed image is not proof that all sensitive content is hidden: preview the redaction in your own tests before attaching the result to AppNorthCreateFeedback.

Read replies as the author

Set a verified identity before creating reports whose replies the user must retrieve. An optional contact email must match the signed email; anonymous reports are not reassigned after login.

ReadReportReplies.swift
import AppNorth

func reportReplies(client: AppNorthClient, reportID: String) async throws -> [AppNorthFeedbackReply] {
    try await client.feedbackThread(reportID).replies
}

Retain the returned report ID using your account-scoped storage. feedbackThread(_:) requires signed identity and returns the report plus public staff replies. It excludes internal notes, contact details, diagnostics, and screenshots. Another user's or project's report returns not found. The SDK has no public report-list method.

Verify

  1. Submit a test report and locate its receipt ID in the dashboard.

  2. Reply publicly as staff and fetch the thread with the original identity.

  3. Try another account and confirm it cannot read the report.

  4. Test capture without consent, a throwing redactor, and unchanged redactor output; all should omit the screenshot.