SAIKAT
Hire me
Open source@pleaseresolve/sdk

@pleaseresolve/sdkv0.3.13

Embeddable issue-reporting widget for Please Resolve — script tag today, npm package in Phase 3.

3,123 / monthcustom licenseUpdated October 4, 2026

Drop-in issue reporting for any website. Paste one script tag or npm install one package, and your visitors can report a bug — with an optional attachment, browser context, and priority — straight into your Please Resolve dashboard. No backend code, no account required on the visitor's side.

<script src="https://nukta-solutions.github.io/pleaseresolve-sdk/widget.js" data-key="pk_live_..." data-project="..."></script>

Contents

Features

  • Zero-friction reporting — a floating Support button, a short form, done. No account, no login, no app to install.
  • Two ways to see it live: a self-updating script tag for any site, or this npm package for a bundled app — same widget either way.
  • Zero-config npm install — set two env vars, import "@pleaseresolve/sdk/auto", and the widget mounts itself. No init() call required in your code.
  • Drag-and-drop attachments — the built-in form has a real attachment dropzone (images and common file types), matching llemr's own report form exactly.
  • "Issues" — a table of every report for the project (not just what one browser submitted), with search, refresh, and a detail view — a 1:1 clone of llemr's real admin Issues page.
  • First-class TypeScript — types ship from the same source as the runtime code.
  • React bindings available as a separate @pleaseresolve/react package.

Install

Get a public-type API key first: Settings → API Keys → Create API Key in your Please Resolve dashboard, keyType: public, with the site(s) you're embedding on listed in allowedOrigins. A public key is locked server-side to creating reports only — it's meant to be embedded in a page anyone can view; see Security model.

Script tag

<script
  src="https://nukta-solutions.github.io/pleaseresolve-sdk/widget.js"
  data-key="pk_live_..."
  data-project="..."
></script>

Paste before </body>. data-project can be omitted if the key is scoped to exactly one project. Full reference: Phase 2 guide.

npm, zero config

npm install @pleaseresolve/sdk
# .env
NEXT_PUBLIC_PLEASERESOLVE_KEY=pk_live_...
NEXT_PUBLIC_PLEASERESOLVE_PROJECT_ID=...   # optional — only if your key covers more than one project
// anywhere in your app's entry point
import "@pleaseresolve/sdk/auto";

That's the whole integration. The widget reads those env vars at your app's own build time and mounts itself — no init() call anywhere in your code. This works because a real bundler (Next.js, Create React App) is what inlines NEXT_PUBLIC_.../REACT_APP_... env vars into the bundle; see src/env.ts for exactly which prefixes are supported and why. Using React? @pleaseresolve/react's <ReportWidget /> reads the same env vars with zero props.

npm, explicit config

Prefer to call init() yourself — explicit values, conditional mounting, a config source other than env vars? Skip @pleaseresolve/sdk/auto and use the API reference below instead. The two approaches aren't meant to be combined.

How it works

Clicking the floating Support button opens a small menu:

  • New Issue — a short form (title, description, priority, and an optional attachment) that submits straight to your dashboard.
  • View Issues — a table of every report submitted for the project through this widget, with search, a Refresh button, and a detail view (matching llemr's real Issues page exactly, not scoped to just the current browser — see Security model for what that means).

Every submission also auto-attaches context (current URL, browser, viewport) with zero configuration.

API reference

import { init, open, close, report, identify, setMetadata, destroy } from "@pleaseresolve/sdk";
// or, from the script tag: window.PleaseResolve.init(...)

init({ key: "pk_live_...", projectId: "...", widget: true });

// Headless mode — drive it from your own trigger button:
init({ key: "pk_live_...", widget: false });
myOwnButton.addEventListener("click", () => open());

// Skip the UI entirely:
await report({ title: "...", description: "...", priority: "high" });

// Pre-fill identity on every subsequent report:
identify({ name: "...", email: "..." });
setMetadata({ plan: "pro" });

// Tear down (React's <ReportWidget /> calls this on unmount):
destroy();
Function What it does
init(options) Mounts the widget. key is required; projectId and apiBaseUrl are optional.
open() / close() Opens/closes the built-in form — for a custom trigger button (widget: false).
report(input) Submits directly, no UI. Never attaches files (only the form's dropzone can).
identify(reporter) Pre-fills identity (name/email) attached to every later report() call. The email also marks who the report's reporter is: only that person gets Reply, and Edit/Delete on their own Discussion messages (edit and delete within 15 minutes of sending). Anyone else viewing can read and post new messages.
setMetadata(obj) Merged into every report's metadata from this point on.
destroy() Unmounts the widget and clears all state.

"View Issues" is backed by GET /api/v1/public/reports (list) and GET /api/v1/public/reports/:id (the Action column's "View"). Both never return comments, internal developer/implementation notes, assignees, or the reporter's email — see pleaseresolve-backend's public-report.service.ts for the exact reasoning behind every field that is or isn't included.

Security model

Two API key types exist for a reason:

public server
Where it's used Script tag, npm bundle — anyone can read it from the page Your own backend, CI, webhooks
Permissions report:create + report:read only, forced server-side Whatever you grant it
Origin check Restricted to allowedOrigins you configure None — no browser involved

Never put a server-type key in a web page. It's not restricted the way a public key is. See the Phase 1 API guide for the full rationale.

"View Issues" lists every report for the project, not just the current visitor's own. Since a public key is readable from the page's own source, this means anyone who can view your page can read every report ever submitted through this widget for that project — titles, descriptions, attachments, and any reporter name given. This was a deliberate trade-off to match a real, organization-facing Issues table rather than a private per-visitor one; if that's not the right model for your use case, don't embed this widget on a page with reports you'd consider sensitive to visitors other than the one who filed them.

Development

npm install
npm run build      # dist/sdk.{js,cjs,d.ts}, dist/auto.{js,cjs}, dist/widget.global.js
npm run typecheck

Three live end-to-end test suites (no mocking — a real local backend, real S3 uploads, real headless Chrome):

node test-e2e.mjs        # the full widget UI: menu, form, attachments, View Issues, detail modal
node test-auto-init.mjs  # @pleaseresolve/sdk/auto specifically — bundles a throwaway app with
                          # esbuild --define (the same substitution Next.js/CRA perform) and
                          # confirms it mounts and submits with zero init() calls anywhere
node test-live-cdn.mjs   # loads the actual hosted script tag from GitHub Pages (not a local
                          # dist/ build) and confirms a real submission through it — rerun this
                          # after any redeploy to catch "the CDN is serving something wrong"
                          # separately from "the local build is wrong"

All three require a local pleaseresolve-backend running on :5000 (docker compose up there); test-live-cdn.mjs additionally needs network access to nukta-solutions.github.io. demo/index.html is also the manual/visual demo — open it after substituting real data-key/data-project values.

See the sibling pleaseresolve-sdk-react repo for React bindings, and GOING_LIVE.md in this workspace for the CDN-hosting and npm-publishing runbook.

License

Proprietary — not open source. This package is publicly installable so Please Resolve clients can npm install it and audit exactly what they're embedding, but it may only be used to integrate with the Please Resolve platform under an active Please Resolve account. See LICENSE for the full terms — no rights to copy, modify, redistribute, or reuse this SDK independently of the Service are granted.

↑↓ navigate↵ openesc closeCtrl K toggles this menu