Product Guide

Guide

Everything you need to know about Signalshoot.

Setup Guide

This guide walks you through the entire process of adding Signalshoot to your app, from creating your account to seeing the first feedback in your dashboard. No prior experience with APIs is assumed.

How It Works (Overview)

Signalshoot works in three simple steps: (1) Your app sends an HTTP request to our server when a user submits feedback. (2) Our server stores the feedback in your dashboard. (3) You open the dashboard to read, organize, and respond. There is no SDK to install. Your app just needs to be able to send an HTTP POST request — which every programming language and framework can do.

Step 1: Get Your Credentials

After signing in to Signalshoot, go to the Settings page. You will find three important values there:

App ID — A unique identifier for your app (e.g., fb_a1b2c3d4e5). This goes into the URL when sending feedback.
Live API Key — Starts with fb_live_. Use this in your production app. Feedback sent with this key appears in your main inbox.
Test API Key — Starts with fb_test_. Use this during development. Test feedback is stored separately and does not clutter your production inbox.
Your credentials
Endpoint: https://api.signalshoot.com/v1/ingest/YOUR_APP_ID
Header: X-API-Key: fb_live_YOUR_KEY

In all code examples below, replace YOUR_APP_ID with your actual App ID, and fb_live_YOUR_KEY (or fb_test_YOUR_KEY) with your actual key. You can copy these directly from Settings.

Step 2: Understand the Request Format

When your app sends feedback to Signalshoot, it sends a JSON object. Here is what each field does:

type (required) — A label that categorizes the feedback. You decide what labels to use. Common examples: "bug" for bug reports, "feedback" for feature requests, "inquiry" for questions. But you can use any name that makes sense for your app: "report", "praise", "crash", "suggestion", or even names in your own language. Each unique type you send automatically appears as a filter button in your dashboard — no setup needed.
message (required) — The actual feedback text written by the user. This is the main content. Maximum 5,000 characters.
channel (optional) — Identifies where in your app the feedback was sent from. For example: "contact-form" if it came from your contact page, "settings-page" if the user used a feedback button in settings, "onboarding" if it came from your onboarding flow. This helps you understand which parts of your app generate the most feedback. Appears as a filter in the dashboard. If omitted, defaults to "default".
user_id (optional) — Your app's identifier for the user who sent the feedback (e.g., a user ID from your database). If you include this, two things become possible: (1) You can reply to the user from the Signalshoot dashboard. (2) Your app can call the replies endpoint to show the developer's response to the user. If omitted, the feedback is anonymous and you cannot reply.
parent_id (optional) — Used for threaded conversations. When a user wants to follow up on an existing feedback (e.g., reply to your response), set this to the ID of the original feedback. The follow-up message is added to the same conversation thread instead of creating a new feedback entry. Important: follow-up messages do not count toward your monthly feedback limit. Only the initial feedback counts.
metadata (optional) — A JSON object containing any additional information you want to attach. Common fields: app_version ("2.1.0"), os ("iOS 18.2"), device ("iPhone 15"), screen ("MapScreen"), locale ("ja-JP"), user_plan ("premium"). This information is displayed as a key-value table in the feedback detail view, helping you understand the context of each report.

Step 3: Add the Code to Your App

Choose your platform below and copy the code. The integration is a single HTTP POST request — no library or SDK to install. Paste the code into your app wherever you want users to be able to send feedback (a contact form, a bug report button, a feedback modal, etc.).

React Native / Expo

Example — React Native
const sendFeedback = async (type, message, channel = 'contact') => {
  await fetch('https://api.signalshoot.com/v1/ingest/YOUR_APP_ID', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-API-Key': 'fb_live_YOUR_KEY',
    },
    body: JSON.stringify({
      type, message, channel,
      metadata: { app_version: Constants.expoConfig?.version, os: Platform.OS },
    }),
  });
};

Flutter (Dart)

Example — Flutter
import 'dart:convert';
import 'package:http/http.dart' as http;

Future<void> sendFeedback(String type, String message) async {
  await http.post(
    Uri.parse('https://api.signalshoot.com/v1/ingest/YOUR_APP_ID'),
    headers: {'Content-Type': 'application/json', 'X-API-Key': 'fb_live_YOUR_KEY'},
    body: jsonEncode({'type': type, 'message': message, 'channel': 'contact'}),
  );
}

Swift (iOS)

Example — Swift
func sendFeedback(type: String, message: String) async throws {
    var req = URLRequest(url: URL(string: "https://api.signalshoot.com/v1/ingest/YOUR_APP_ID")!)
    req.httpMethod = "POST"
    req.setValue("application/json", forHTTPHeaderField: "Content-Type")
    req.setValue("fb_live_YOUR_KEY", forHTTPHeaderField: "X-API-Key")
    req.httpBody = try JSONSerialization.data(withJSONObject: [
        "type": type, "message": message, "channel": "contact"
    ])
    let (_, _) = try await URLSession.shared.data(for: req)
}

Kotlin (Android)

Example — Kotlin
val body = JSONObject().apply {
    put("type", "bug"); put("message", msg); put("channel", "contact")
}.toString().toRequestBody("application/json".toMediaType())

val request = Request.Builder()
    .url("https://api.signalshoot.com/v1/ingest/YOUR_APP_ID")
    .addHeader("X-API-Key", "fb_live_YOUR_KEY")
    .post(body).build()

OkHttpClient().newCall(request).execute()

Web (JavaScript)

Example — JavaScript
await fetch('https://api.signalshoot.com/v1/ingest/YOUR_APP_ID', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', 'X-API-Key': 'fb_live_YOUR_KEY' },
  body: JSON.stringify({ type: 'bug', message: msg, channel: 'contact' }),
});

Important for web apps: Your API key will be visible in browser source code if you include it in client-side JavaScript. For web applications, we strongly recommend sending the API request from your backend server instead. This keeps your key hidden from users.

Alternative: Let AI Write the Code for You

If you use an AI coding assistant like Claude, Cursor, or GitHub Copilot, you don't need to write the integration code yourself. Copy the prompt below and paste it into your AI assistant. It contains all the information the AI needs to generate the correct code for your specific app and platform.

Prompt template
Add a feedback button to my app that sends user feedback to Signalshoot.

API endpoint: https://api.signalshoot.com/v1/ingest/MY_APP_ID
API key: fb_live_MY_KEY (send as X-API-Key header)

Request body (JSON):
- type: "bug" | "feedback" | "inquiry" (required)
- message: string (required, max 5000 chars)
- channel: string (optional, e.g. "contact", "report")
- user_id: string (optional, enables replies)
- metadata: object (optional, e.g. { app_version, os, device, screen })

Step 4: Enable Two-Way Communication (Optional)

By default, feedback is one-way: users send, you read. But if you include a user_id when sending feedback, you unlock two-way communication. Here's how it works: (1) User sends feedback with user_id included. (2) You see it in the dashboard and write a reply. (3) Your app calls the replies endpoint to check if there's a response. (4) Your app displays the reply to the user. For threaded follow-ups, the user sends a new request with parent_id set to the original feedback ID.

Example — Replies
// Include user_id when sending:
{ type: 'bug', message: '...', user_id: 'user_123' }

// Fetch replies:
GET https://api.signalshoot.com/v1/feedback/YOUR_APP_ID/replies?user_id=user_123
X-API-Key: fb_live_YOUR_KEY

Step 5: Test Before Going Live

Before releasing your app with Signalshoot integrated, test the entire flow: (1) Send a test feedback using your test API key (fb_test_...). (2) Open the Signalshoot dashboard and verify it appears. (3) Try changing the status, adding tags, and writing a reply. (4) If you implemented replies, verify your app can fetch them. (5) Once everything works, switch to the live API key in your production build.

Example — cURL
curl -X POST https://api.signalshoot.com/v1/ingest/YOUR_APP_ID \
  -H "Content-Type: application/json" \
  -H "X-API-Key: fb_live_YOUR_KEY" \
  -d '{"type":"bug","channel":"contact","message":"Test from cURL"}'

Your test key (fb_test_...) works exactly like the live key, but feedback sent with it is marked as test data and stored separately. This means you can test freely without cluttering your production inbox. You can also use the "Send test feedback" button in Settings to quickly verify your dashboard is working.