On this page

Pingkit Documentation

Getting Started

PingKit is a lightweight, privacy-first feedback SDK for iOS. It gives your users a native SwiftUI modal to send text and screenshots, while you get a dashboard to triage everything. Two lines of Swift to integrate.

Prerequisites:

  • Xcode 15 or later
  • iOS 16.0+ deployment target
  • Swift 5.9+
  • A Pingkit account - sign up here

Installation

PingKit is distributed via Swift Package Manager. No CocoaPods, no Carthage, no binary frameworks.

Option A: Xcode GUI

In Xcode, go to File → Add Package Dependencies and enter the repository URL:

Repository URL
https://github.com/pingkitdev/pingkit-swift.git

Set the dependency rule to Up to Next Major Version from 1.0.0.

Option B: Package.swift

Add PingKit to your package dependencies:

Package.swift
// Package.swift dependencies: [ .package(url: "https://github.com/pingkitdev/pingkit-swift.git", from: "1.0.0") ]

Configuration

Call PingKit.configure() once at app launch -typically in your App initializer. You'll find your API key in the dashboard settings.

MyApp.swift
import PingKit @main struct MyApp: App { init() { PingKit.configure(apiKey: "pk_proj_xxxxxxxxxxxx") } var body: some Scene { WindowGroup { ContentView() } } }

Advanced Options

Pass a PingKitOptions struct for additional configuration:

Advanced configuration
PingKit.configure( apiKey: "pk_proj_xxxxxxxxxxxx", options: PingKitOptions( endpoint: "https://pingkit.dev", enableAppAttest: true, maxImageSizeMB: 5, verbose: false ) )
OptionDefaultDescription
endpoint"https://pingkit.dev"API endpoint URL
enableAppAttesttrueEnable Apple App Attest for device verification
maxImageSizeMB5Maximum screenshot size in MB before JPEG compression
verbosefalseEnable debug logging to the console

Show Feedback Modal

Call PingKit.show() to present the native feedback modal. Attach it to any button, gesture, or event in your app.

Basic usage
Button("Send Feedback") { PingKit.show() }

Email Field

Control whether the email field appears and how it behaves:

Email options
// Optional, user can skip it PingKit.show(email: .optional) // Required, user must fill it in PingKit.show(email: .required) // Pre-filled from your auth system PingKit.show(email: .prefilled("user@example.com"))

Type Picker

Add a category picker so users can classify their feedback:

Type picker
PingKit.show(type: .picker(["Bug", "Feature Request", "Question"]))

Custom Metadata

Attach arbitrary key-value pairs that show up in the dashboard:

Metadata
PingKit.show(metadata: ["screen": "settings", "user_tier": "premium"])

Everything Together

Combined example
PingKit.show( email: .optional, type: .picker(["Bug", "Feature", "Other"]), metadata: ["screen": "checkout", "user_tier": "premium"] )

Headless Mode

Don't want the built-in modal? Use PingKit.submit() to send feedback from your own UI. The dashboard, webhooks, and all backend features work exactly the same.

Headless submission
do { let result = try await PingKit.submit( text: "The save button doesn't work", image: screenshotData, email: "user@example.com", type: "bug", metadata: ["screen": "editor"] ) print("Feedback submitted: \(result.id)") } catch { print("Submission failed: \(error)") }

Error Handling

The SDK provides typed errors you can handle in headless mode:

Error handling
do { try await PingKit.submit(text: "feedback") } catch PingKitError.networkError(let urlError) { // DNS failure, timeout, no connection } catch PingKitError.rateLimited(let retryAfter) { // Too many requests, wait retryAfter seconds } catch PingKitError.unauthorized { // Invalid API key } catch PingKitError.planLimitReached { // Monthly quota exceeded } catch { // Other error }

Theming

Customize the feedback modal to match your app's look. Pass a PingKitTheme to configure().

Theming
PingKit.configure( apiKey: "pk_proj_xxxxxxxxxxxx", theme: PingKitTheme( accentColor: .blue, backgroundColor: Color(uiColor: .systemBackground), cardColor: Color(uiColor: .secondarySystemBackground), cornerRadius: 16, font: .body ) )
PropertyDefaultDescription
accentColor.accentColorButtons and interactive elements
backgroundColor.systemBackgroundModal background color
cardColornilSection card background (nil uses iOS default)
cornerRadius20Modal corner radius in points
font.bodyBase font for modal text

App Attest

Pingkit uses Apple App Attest to verify that feedback submissions come from a genuine instance of your app running on real Apple hardware. This prevents API abuse from bots, scripts, and modified app builds.

How It Works

  • The SDK generates a device-specific cryptographic key on first launch and stores it securely in the Keychain
  • Each feedback submission includes a signed assertion that the server validates
  • Attested requests get your full rate limit (default 100/hr). Unattested requests are limited to 10/hr.
  • App Attest is enabled by default -the SDK handles everything automatically

Xcode Setup

To enable App Attest, add the capability to your Xcode project:

  1. Open your project in Xcode and select your app target
  2. Go to the Signing & Capabilities tab
  3. Click + Capability
  4. Search for App Attest and add it

This adds the com.apple.developer.devicecheck.app-attest entitlement to your app. No additional code is needed -the SDK detects the capability and uses it automatically.

Development & Simulators

App Attest is not available on the iOS Simulator or older devices. The SDK handles this gracefully:

  • Simulator / unsupported devices -submissions still work, but with the stricter unattested rate limit (10 requests/hr)
  • Disable during development -set enableAppAttest: false in your PingKitOptions, or toggle off "Require App Attest" in dashboard Settings
Disable App Attest for testing
PingKit.configure( apiKey: "pk_proj_xxxxxxxxxxxx", options: PingKitOptions( enableAppAttest: false ) )

Dashboard Settings

Each project has a Require App Attest toggle in the dashboard settings. When enabled, requests without a valid App Attest assertion are rejected with a 403 ATTEST_REQUIRED error. Disable this if you need to accept requests from non-iOS clients or during development.

Dashboard

The Pingkit dashboard is where you triage feedback, manage projects, and configure your account. Everything your users submit lands here in real time.

Signing In

Sign in with your GitHub account. Pingkit uses GitHub OAuth -no passwords to manage, no separate auth system. After signing in, you'll land on your feedback list or the onboarding flow if it's your first time.

Projects

Each project represents one iOS app. When you create a project, Pingkit generates an API key (prefixed with pk_) that you pass to PingKit.configure() in your app. You can create multiple projects for different apps or environments (e.g. staging vs. production).

Feedback List

The feedback page shows every submission across your project. You can filter by status (new, in progress, resolved), search by text content, and narrow by date range. Feedback is sorted by newest first, with pagination for large volumes.

Each row shows the feedback text preview, status badge, device info, and timestamp. Click any row to open the detail view.

Detail View

The detail view shows the full feedback text, any attached screenshot, device metadata (model, OS version, app version, locale, timezone), and custom metadata you passed via the SDK. From here you can:

  • Update the status (new → in progress → resolved)
  • Add internal notes for your team
  • View the full-resolution screenshot
  • See all auto-collected device information

Settings

In settings you can manage your project's API key, webhook URL, and billing. Key features:

  • API key rotation -Generate a new key with a 24-hour grace period for the old one
  • Webhooks -Set a URL to receive a POST request whenever new feedback arrives. Pipe it to Slack, Discord, or your own tooling.
  • Billing -Manage your subscription via Stripe. Upgrade, downgrade, or view invoices.

MCP Integration

Pingkit ships an MCP server so your AI coding assistant can read, search, and triage feedback without leaving the editor. Works with Claude Code, Cursor, Codex, Windsurf, and any tool that supports the Model Context Protocol. The server is open source on GitHub.

Setup

1. Create a personal access token in the dashboard settings under "Personal Access Tokens". The token is shown once -copy it immediately.

2. Add to your project's MCP config. Create or edit .mcp.json in your project root:

.mcp.json
{ "mcpServers": { "pingkit": { "command": "npx", "args": ["-y", "@pingkit/mcp"], "env": { "PINGKIT_TOKEN": "pt_your_token_here" } } } }

That's it. Your AI tool will pick up the config and connect to Pingkit automatically. Requires Node.js 18+.

Token Security

  • Tokens are scoped to your account -they can access all your projects and feedback
  • Tokens expire after 365 days. You can revoke them anytime from settings.
  • Maximum 5 tokens per account
  • Add .mcp.json to your .gitignore if it contains a real token

Tools

The MCP server exposes seven tools your AI assistant can call:

ToolDescription
list_feedbackSearch and filter feedback with pagination. Filter by status, app version, date range, or free-text search.
get_feedbackGet full details of a single feedback item including metadata and notes.
update_feedbackUpdate status (new, acknowledged, resolved, archived) or add internal notes.
bulk_feedbackPerform bulk actions (acknowledge, archive, delete) on up to 100 items at once.
feedback_statsGet submission timeline and app version breakdown for analytics.
list_projectsList all your projects with their configuration.
get_quotaCheck your current plan, submission count, and quota.

Prompts

Three built-in prompts give your AI assistant a starting point for common workflows:

PromptWhat it does
triageReviews all unresolved feedback, groups by theme, and suggests priorities.
release_reviewSummarizes feedback for a specific app version -great before or after a release.
trendsAnalyzes submission volume, version distribution, and emerging patterns.

You can also talk to your assistant naturally -it will call the right tools automatically. Try things like "What are users complaining about in v2.3?" or "Mark all dark mode feedback as resolved".

Auto-Collected Metadata

Every feedback submission automatically includes device context. You don't need to collect or pass this -the SDK handles it.

FieldExample
Device ModeliPhone 15 Pro
OS Version18.2
App Version1.2.0
Build Number42
Localeen_US
TimezoneEurope/Zurich

Privacy

Pingkit is built with privacy as a core principle. Here's exactly what data flows through the system and how it's handled.

What We Collect

  • Feedback text -the message your user explicitly writes and submits
  • Optional screenshot -only if the user chooses to attach one
  • Device metadata -model, OS version, app version, build number, locale, and timezone (auto-collected by the SDK for bug reproduction)
  • Custom metadata -any key-value pairs you pass via the SDK (e.g. screen name, user tier)

What We Don't Collect

  • No analytics or usage tracking
  • No background data collection
  • No advertising identifiers
  • No PII beyond what the user explicitly submits
  • No network calls except when the user taps "Send"

Data Storage

  • All data is stored on Cloudflare's global edge network (D1 for structured data, R2 for screenshots), encrypted at rest
  • Screenshots have EXIF metadata stripped before storage and are served via time-limited signed URLs (15-minute expiry)
  • API keys are stored as SHA-256 hashes -even a database breach won't expose raw keys

Data Retention

Feedback is automatically deleted after 6 months (180 days), including associated screenshots. This runs daily via an automated cleanup job.

Open Source SDK

The iOS SDK is fully open source with zero third-party dependencies. You can audit every line of code that ships inside your app at github.com/pingkitdev/pingkit-swift.

Data Export & Deletion

You can export all your data or delete your account entirely from the dashboard settings page. Account deletion removes all users, projects, feedback, sessions, and stored screenshots permanently.

Terms of Service

Effective date: February 14, 2026. By using Pingkit, you agree to these terms.

1. Service Description

Pingkit provides an in-app feedback SDK for iOS and a web dashboard for managing user feedback. The service includes feedback collection, screenshot storage, webhook notifications, and an MCP server for AI coding tools.

2. Account Requirements

You must sign in with a GitHub account that has a verified email address. You are responsible for maintaining the security of your account and API keys. You must be at least 16 years old to use the service.

3. Acceptable Use

You agree not to:

  • Use the service for any unlawful purpose or to collect illegal content
  • Abuse, scrape, or reverse-engineer the API beyond its documented interface
  • Attempt to access other users' data or bypass authentication
  • Submit malicious content, malware, or intentionally harmful data
  • Resell or redistribute the service without written permission

4. Payment Terms

Pingkit offers two plans: Indie ($5/mo, 1 project) and Pro ($9.99/mo, unlimited projects), billed through Stripe. You can cancel anytime from the dashboard settings page. Cancellation takes effect at the end of the current billing period. No refunds are issued for partial months. If payment fails, your account may be downgraded or suspended after a grace period.

5. Data Handling

Your use of Pingkit is also governed by our Privacy Policy, which describes what data we collect, how we store it, and your rights under GDPR. Feedback data is retained for 180 days (6 months) and then automatically deleted.

6. Intellectual Property

You retain full ownership of all feedback data submitted through your projects. Pingkit does not claim any rights to your content. The Pingkit platform, SDK, dashboard, API, and documentation are owned by Pingkit. The iOS SDK is licensed under the Apache 2.0 open source license.

7. Service Availability

We strive to keep Pingkit available and reliable, but we do not guarantee any specific uptime or SLA. The service runs on Cloudflare's global edge network. We may perform maintenance or updates that temporarily affect availability. We will make reasonable efforts to notify you of planned downtime in advance.

8. Limitation of Liability

Pingkit is provided "as is" without warranties of any kind, express or implied. To the maximum extent permitted by law, Pingkit shall not be liable for any indirect, incidental, special, or consequential damages, including loss of data, revenue, or business opportunities. Our total liability is limited to the amount you paid for the service in the 12 months preceding the claim.

9. Termination

Either party may terminate the agreement at any time. You can delete your account from the dashboard settings page. Upon account deletion, all your data (projects, feedback, screenshots, sessions) is permanently and irreversibly removed. We may suspend or terminate accounts that violate these terms, with notice where practical.

10. Changes to Terms

We may update these terms from time to time. When we make material changes, we will notify you via the email address associated with your GitHub account. Continued use of the service after changes take effect constitutes acceptance of the updated terms.

11. Contact

For questions about these terms, contact us at hello@pingkit.dev.

FAQ

What data does PingKit collect?
Only what the user explicitly sends: their text feedback and an optional screenshot. The SDK also attaches device metadata (model, OS version, app version, locale, timezone) so you can reproduce bugs. There is no analytics, no tracking, and no background data collection.
Is the SDK open source?
Yes. The iOS SDK is fully open source under the Apache 2.0 license at github.com/pingkitdev/pingkit-swift. You can audit every line that ships in your app.
Can I use my own UI instead of the built-in modal?
Absolutely. Use PingKit.submit() in headless mode to send feedback from any custom view. The dashboard, webhooks, and all backend features work the same way regardless of which submission method you use.
What iOS versions are supported?
iOS 16.0 and later. The SDK requires Swift 5.9+ and Xcode 15+.
How does billing work?
Pingkit starts at $5/month (Indie, 1 project) or $9.99/month (Pro, unlimited projects). Unlimited feedback on both plans, 6-month data retention. No per-user pricing, no MAU tiers. Billing is handled through Stripe and managed from the dashboard settings page.
Can I self-host Pingkit?
Not currently. Pingkit runs on Cloudflare's edge network for performance and reliability. The SDK is open source so you can always audit what runs in your app.
How do webhooks work?
When new feedback is submitted, Pingkit sends a POST request to the webhook URL you configure in settings. The payload includes the feedback text, metadata, and a link to the dashboard. Use it to post to Slack, trigger a Discord notification, send an email, or integrate with any tool that accepts webhooks.
Does PingKit work with UIKit?
The built-in feedback modal is SwiftUI, but you can use PingKit.submit() in headless mode from any UIKit view controller. Build your own UIKit form and call submit() with the text, image, and metadata. The backend works identically.
Will PingKit slow down my app?
No. The SDK has zero background processes and makes no network calls until the user taps Send. The compiled framework adds under 200KB to your binary. There is no startup overhead, no polling, and no analytics running in the background.
Does PingKit comply with GDPR and App Store guidelines?
Yes. PingKit collects only user-initiated feedback (text + optional screenshot) and device metadata for bug reproduction. No tracking, no advertising identifiers, no background data collection. The SDK is open source so you can verify this. Screenshots have EXIF metadata stripped before storage. Data is automatically deleted after 6 months.
What happens to screenshots after upload?
Screenshots are validated (magic byte check for JPEG/PNG), stripped of all EXIF metadata, and stored in Cloudflare R2 with private access only. They are served via time-limited signed URLs that expire after 15 minutes. Screenshots are automatically deleted after 6 months along with their associated feedback.
How is PingKit different from Instabug?
PingKit is built for indie devs and small teams. Key differences: from $5/mo pricing (no per-MAU costs), zero SDK dependencies, open source SDK you can audit, MCP server for AI coding tools, and privacy-first design with no analytics or tracking. Instabug targets enterprises with crash reporting, performance monitoring, and surveys. PingKit does one thing well: in-app feedback.
Can I export my data?
Yes. You can export all your feedback data from the dashboard settings page. You can also delete your entire account, which permanently removes all projects, feedback, screenshots, and sessions.
What is the uptime and reliability?
Pingkit runs on Cloudflare Workers, which deploys your API to 300+ edge locations worldwide. D1 handles the database, R2 handles screenshot storage. There is no single server to go down. The SDK handles network errors gracefully and never crashes the host app.
Does App Attest work on simulators?
No. Apple App Attest requires real hardware with a Secure Enclave. On simulators and unsupported devices, the SDK falls back to unattested mode with a stricter rate limit (10 requests/hr instead of your project limit). You can also disable App Attest entirely via PingKitOptions for development.