Point the official Sentry SDK at self-hosted ingest (DSN only)
We need to reformat the article into clean Markdown with sections, bullet lists, code blocks, preserving facts. No extra commentary. Output only reformatted article body.
We need to break into paragraphs, add headings where topic shifts. Use bullet or numbered lists for enumerations. Use inline code or fenced code blocks for code/commands/identifiers.
We must preserve every fact, name, number, quotation exactly. No adding or removing info.
We need to output only the reformatted article body as Markdown, nothing else.
Let's parse the article content.
The article starts with: "You don’t need a forked Sentry SDK. Keep @sentry/browser or @sentry/node , change only dsn , then prove /health → HTTP 202 → Issues. Two containers (app + Postgres 16); leave replay, traces, and profiles at sample rate 0 - those envelope items are out of scope. What you will do Clone and docker compose up Confirm GET /health → {"status":"ok"} Install a pinned official SDK ( 7.120.0 ) Sentry.init with your DSN and zeroed unused sample rates captureException and expect ingest 202 , then an Issues row Optional: raw store / envelope curls if the SDK path is noisy Two containers, one health check Clone the public tree and start compose from the repo root: git clone https://github.com/epure-sh/epure.git cd epure docker compose up Two services: the app image and postgres:16-alpine . No Redis. No separate worker fleet on this laptop path. If port 8080 is taken: cp .env.example .env # set EPURE_PORT and EPURE_PUBLIC_URL together, then recreate the app container Wait for health: curl -sS http://localhost:8080/health Expected body: { "status" : "ok" } Open http://localhost:8080 . Register in the UI, or for local smoke only (never production): ./scripts/seed-dev.sh Copy the DSN (only thing that changes) From the dashboard: Settings → SDK connection (or the setup checklist). Create a key if none exists. Shape: http://{public_key}@localhost:8080/{project_id} Migrating from Sentry SaaS? Keep the same init options. Replace only dsn . Init once, throw once Pin the fixtures the public docs exercise: # browser SPA npm install @sentry/browser@7.120.0 # or Node API / worker npm install @sentry/node@7.120.0 Browser example: import * as Sentry from " @sentry/browser " ; Sentry . init ({ dsn : " http://YOUR_PUBLIC_KEY@localhost:8080/YOUR_PROJECT_ID " , environment : " local " , release : " my-app@0.0.0 " , tracesSampleRate : 0 , profilesSampleRate : 0 , replaysSessionSampleRate : 0 , replaysOnErrorSampleRate : 0 , }); Sentry . captureException ( new Error ( " Epure quickstart test " )); Node is the same shape with @sentry/node . Set unused sample rates to 0 . Transactions, session replay, and profiles are discarded on an exception-only host - zeroing them stops the SDK from sending work you will never see in Issues. Confirm 202, then Issues Ingest accepts before the Issues row appears. A successful SDK or store/envelope POST returns HTTP 202 with a body like: { "id" : "660e8400-e29b-41d4-a716-446655440001" } Refresh http://localhost:8080 . Match the environment filter chip to Sentry.init ( local in the example). You want an unresolved issue for Error / Epure quickstart test . Empty feed copy looks like 0 UNRESOLVED EXCEPTIONS . That alone is not proof of failure - see the checklist below. Optional: curl without an SDK Useful when you need to separate “SDK wiring” from “host ingest.” Seed IDs below match ./scripts/seed-dev.sh in the public docs. Change host if EPURE_PORT is not 8080 . Legacy store JSON: curl -sS -D - -o /tmp/epure-ingest.json -X POST \ "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/store/" \ -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \ -H "Content-Type: application/json" \ -d '{ "platform": "javascript", "exception": { "values": [{ "type": "Error", "value": "Epure try-it" }] } }' Expect HTTP/1.1 202 Accepted and an id in the JSON body. Envelope path (same auth, binary body from the repo): curl -sS -D - -o /tmp/epure-envelope.json -X POST \ "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/envelope/" \ -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \ -H "Content-Type: application/x-sentry-envelope" \ --data-binary @fixtures/sentry/browser/envelope.txt Endpoints that matter: Method Path POST /api/{project_id}/store/ POST /api/{project_id}/envelope/ GET /health When 202 is a lie 202 means auth + schema accepted. It is non-blocking. It does not mean “row visible in Issues yet.” Checklist when the feed stays empty after a 202 : Wait, then refresh - accept is ahead of the worker. One immediate refresh is not final. Environment chip - UI filter must match environment in Sentry.init ( local in the examples). Project / DSN mismatch - open the project that owns the key you put in dsn . Wrong host or port - EPURE_PUBLIC_URL / EPURE_PORT drift after a .env change without recreating the app container. SDK still talking to SaaS - leftover dsn , or a second Sentry.init later in boot. If store curl returns 202 but the SDK path does not, debug the client. If both miss 202 , debug the host ( docker compose logs on the app service, health, DSN key). What this host is not Exception-only lane. Do not expect APM, session replay, profiling, log product, or mobile SDKs to “just work” because the DSN looks familiar. JS/TS source maps are a separate verify step (upload + prove demangled frames) - out of scope here. Do not write “100% Sentry compatible” in a PR description or a README badge. Honest subset: official SDK, DSN swap, exceptions, envelope/store. FAQ Does Sentry JS 8.x work? Often yes. CI fixtures are 7.120.0 . On v8+, set enableTracing: false when the option exists, and keep traces / profiles / replay sample rates at 0 . Pin 7.120.0 if you want the same line the docs exercise. Confirm with a real throw, not only a green install. Can I use Python or curl only? Yes. Envelope and store accept official Sentry SDKs and raw JSON. Store is the smallest wire path. Phase 1 demangle stays JS/TS only, so frames stay as sent for other runtimes. Do I need Redis? No. Two containers for this path: app + Postgres 16. Laptop compose in production? No. Use the production overlay and a real .env from .env.production.example . Seed script and example DB passwords are local smoke only. Canonical docs Quickstart (this flow): https://epure.sh/docs/get-started/quickstart Install / Postgres 16 / prod overlay: https://epure.sh/docs/self-hosting/installation If those URLs 404 someday, the commands above still stand: health JSON, store/envelope 202 , DSN host swap, sample rates at 0 . Discussion After ingest returns 202 but Issues stays empty - do you check the environment chip, project/DSN match, or worker lag first?
Then there is a duplicate block: "You don’t need a forked Sentry SDK. Keep @sentry/browser or @sentry/node , change only dsn , then prove /health → HTTP 202 → Issues. Two containers (app + Postgres 16); leave replay, traces, and profiles at sample rate 0 - those envelope items are out of scope. What you will do - Clone and docker compose up - Confirm GET /health →{"status":"ok"} - Install a pinned official SDK ( 7.120.0 ) - Sentry.init with your DSN and zeroed unused sample rates - captureException and expect ingest202 , then an Issues row - Optional: raw store /envelope curls if the SDK path is noisy Two containers, one health check Clone the public tree and start compose from the repo root: git clone https://github.com/epure-sh/epure.git cd epure docker compose up Two services: the app image and postgres:16-alpine . No Redis. No separate worker fleet on this laptop path. If port 8080 is taken: cp .env.example .env # set EPURE_PORT and EPURE_PUBLIC_URL together, then recreate the app container Wait for health: curl -sS http://localhost:8080/health Expected body: {"status":"ok"} Open http://localhost:8080 . Register in the UI, or for local smoke only (never production): ./scripts/seed-dev.sh Copy the DSN (only thing that changes) From the dashboard: Settings → SDK connection (or the setup checklist). Create a key if none exists. Shape: http://{public_key}@localhost:8080/{project_id} Migrating from Sentry SaaS? Keep the same init options. Replace only dsn . Init once, throw once Pin the fixtures the public docs exercise: # browser SPA npm install @sentry/browser@7.120.0 # or Node API / worker npm install @sentry/node@7.120.0 Browser example: import * as Sentry from "@sentry/browser"; Sentry.init({ dsn: "http://YOUR_PUBLIC_KEY@localhost:8080/YOUR_PROJECT_ID", environment: "local", release: "my-app@0.0.0", tracesSampleRate: 0, profilesSampleRate: 0, replaysSessionSampleRate: 0, replaysOnErrorSampleRate: 0, }); Sentry.captureException(new Error("Epure quickstart test")); Node is the same shape with @sentry/node . Set unused sample rates to 0 . Transactions, session replay, and profiles are discarded on an exception-only host - zeroing them stops the SDK from sending work you will never see in Issues. Confirm 202, then Issues Ingest accepts before the Issues row appears. A successful SDK or store/envelope POST returns HTTP 202 with a body like: { "id": "660e8400-e29b-41d4-a716-446655440001" } Refresh http://localhost:8080 . Match the environment filter chip to Sentry.init (local in the example). You want an unresolved issue for Error / Epure quickstart test . Empty feed copy looks like 0 UNRESOLVED EXCEPTIONS . That alone is not proof of failure - see the checklist below. Optional: curl without an SDK Useful when you need to separate “SDK wiring” from “host ingest.” Seed IDs below match ./scripts/seed-dev.sh in the public docs. Change host if EPURE_PORT is not 8080 . Legacy store JSON: curl -sS -D - -o /tmp/epure-ingest.json -X POST \ "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/store/" \ -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \ -H "Content-Type: application/json" \ -d '{ "platform": "javascript", "exception": { "values": [{ "type": "Error", "value": "Epure try-it" }] } }' Expect HTTP/1.1 202 Accepted and an id in the JSON body. Envelope path (same auth, binary body from the repo): curl -sS -D - -o /tmp/epure-envelope.json -X POST \ "http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/envelope/" \ -H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \ -H "Content-Type: application/x-sentry-envelope" \ --data-binary @fixtures/sentry/browser/envelope.txt Endpoints that matter: | Method | Path | |---|---| POST | /api/{project_id}/store/ | POST | /api/{project_id}/envelope/ | GET | /health | When 202 is a lie 202 means auth + schema accepted. It is non-blocking. It does not mean “row visible in Issues yet.” Checklist when the feed stays empty after a 202 : - Wait, then refresh - accept is ahead of the worker. One immediate refresh is not final. - Environment chip - UI filter must match environment inSentry.init (local in the examples). - Project / DSN mismatch - open the project that owns the key you put in dsn . - Wrong host or port - EPURE_PUBLIC_URL /EPURE_PORT drift after a.env change without recreating the app container. - SDK still talking to SaaS - leftover dsn , or a secondSentry.init later in boot. If store curl returns 202 but the SDK path does not, debug the client. If both miss 202 , debug the host (docker compose logs on the app service, health, DSN key). What this host is not Exception-only lane. Do not expect APM, session replay, profiling, log product, or mobile SDKs to “just work” because the DSN looks familiar. JS/TS source maps are a separate verify step (upload + prove demangled frames) - out of scope here. Do not write “100% Sentry compatible” in a PR description or a README badge. Honest subset: official SDK, DSN swap, exceptions, envelope/store. FAQ Does Sentry JS 8.x work? Often yes. CI fixtures are 7.120.0 . On v8+, set enableTracing: false when the option exists, and keep traces / profiles / replay sample rates at 0 . Pin 7.120.0 if you want the same line the docs exercise. Confirm with a real throw, not only a green install. Can I use Python or curl only? Yes. Envelope and store accept official Sentry SDKs and raw JSON. Store is the smallest wire path. Phase 1 demangle stays JS/TS only, so frames stay as sent for other runtimes. Do I need Redis? No. Two containers for this path: app + Postgres 16. Laptop compose in production? No. Use the production overlay and a real .env from .env.production.example . Seed script and example DB passwords are local smoke only. Canonical docs - Quickstart (this flow): https://epure.sh/docs/get-started/quickstart - Install / Postgres 16 / prod overlay: https://epure.sh/docs/self-hosting/installation If those URLs 404 someday, the commands above still stand: health JSON, store/envelope 202 , DSN host swap, sample rates at 0 . Discussion After ingest returns 202 but Issues stays empty - do you check the environment chip, project/DSN match, or worker lag first? Top comments (0)"
Essentially the article is duplicated. We need to preserve every fact, but we should not duplicate? The instruction: "Preserve every fact, name, number, and quotation exactly as given. Never invent, add, remove, or reorder information." If the source contains duplicate blocks, we must preserve them as they appear? It says "Never ... remove ... information." So we must keep the duplicate content as is. However, we can restructure but not remove. So we need to output the same content, just reformatted with markdown.
Thus we need to keep the duplicated sections exactly as they appear (including the duplicate). We'll just reformat the whole text.
We need to break into paragraphs, add headings where topic shifts. Identify logical sections: Introduction, What you will do, Clone and docker compose up, Health check, Register and DSN, SDK initialization, Confirm 202 then Issues, Optional curl without SDK, Endpoints that matter, When 202 is a lie, Checklist, What this host is not, FAQ, Discussion, maybe duplicate again.
We need to preserve the duplicate block after the first large block. So after the first block ends (maybe after "Discussion After ingest returns 202 but Issues stays empty - do you check the environment chip, project/DSN match, or worker lag first?"), then there is again "You don’t need a forked Sentry SDK..." So we need to repeat the same sections again.
Thus final markdown will have two identical sections (maybe with same headings). We'll just reformat the whole thing.
We need to use code fences for commands and code snippets. Use inline code for identifiers like @sentry/browser, dsn, etc.
We need to preserve exact quotations, including spaces and punctuation. Ensure we don't alter them.
Let's craft.
We'll start with a heading? The instruction: "Do not repeat the article title as a heading". So we should not add a heading for the title. We can start with a paragraph.
We'll break into sections with ## headings.
Let's outline:
Overview
Paragraph: You don’t need a forked Sentry SDK...
What you will do
List: - Clone and docker compose up
- Confirm GET /health → {"status":"ok"}
- Install a pinned official SDK ( 7.120.0 )
- Sentry.init with your DSN and zeroed unused sample rates
- captureException and expect ingest 202 , then an Issues row
- Optional: raw store / envelope curls if the SDK path is noisy
Two containers, one health check
Paragraph: Clone the public tree and start compose from the repo root: git clone https://github.com/epure-sh/epure.git cd epure docker compose up
Two services: the app image and postgres:16-alpine . No Redis. No separate worker fleet on this laptop path.
If port 8080 is taken: cp .env.example .env # set EPURE_PORT and EPURE_PUBLIC_URL together, then recreate the app container
Wait for health: curl -sS http://localhost:8080/health
Expected body: { "status" : "ok" }
Open http://localhost:8080 . Register in the UI, or for local smoke only (never production): ./scripts/seed-dev.sh
Copy the DSN (only thing that changes)
From the dashboard: Settings → SDK connection (or the setup checklist). Create a key if none exists.
Shape: http://{public_key}@localhost:8080/{project_id}
Migrating from Sentry SaaS? Keep the same init options. Replace only dsn .
Init once, throw once
Pin the fixtures the public docs exercise:
browser SPA npm install @sentry/browser@7.120.0
or Node API / worker npm install @sentry/node@7.120.0
Browser example:
import * as Sentry from "@sentry/browser";
Sentry.init({
dsn: "http://YOUR_PUBLIC_KEY@localhost:8080/YOUR_PROJECT_ID",
environment: "local",
release: "my-app@0.0.0",
tracesSampleRate: 0,
profilesSampleRate: 0,
replaysSessionSampleRate: 0,
replaysOnErrorSampleRate: 0,
});
Sentry.captureException(new Error("Epure quickstart test"));
Node is the same shape with @sentry/node . Set unused sample rates to 0 .
Transactions, session replay, and profiles are discarded on an exception-only host - zeroing them stops the SDK from sending work you will never see in Issues.
Confirm 202, then Issues
Paragraph: Ingest accepts before the Issues row appears. A successful SDK or store/envelope POST returns HTTP 202 with a body like: { "id" : "660e8400-e29b-41d4-a716-446655440001" }
Refresh http://localhost:8080 . Match the environment filter chip to Sentry.init ( local in the example). You want an unresolved issue for Error / Epure quickstart test . Empty feed copy looks like 0 UNRESOLVED EXCEPTIONS . That alone is not proof of failure - see the checklist below.
Optional: curl without an SDK
Paragraph: Useful when you need to separate “SDK wiring” from “host ingest.” Seed IDs below match ./scripts/seed-dev.sh in the public docs. Change host if EPURE_PORT is not 8080 .
Legacy store JSON:
curl -sS -D - -o /tmp/epure-ingest.json -X POST \
"http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/store/" \
-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \
-H "Content-Type: application/json" \
-d '{ "platform": "javascript", "exception": { "values": [{ "type": "Error", "value": "Epure try-it" }] } }'
Expect HTTP/1.1 202 Accepted and an id in the JSON body.
Envelope path (same auth, binary body from the repo):
curl -sS -D - -o /tmp/epure-envelope.json -X POST \
"http://localhost:8080/api/550e8400-e29b-41d4-a716-446655440000/envelope/" \
-H "X-Sentry-Auth: Sentry sentry_version=7, sentry_key=a1b2c3d4e5f6g7h8i9j0, sentry_secret=supersecretdevkey" \
-H "Content-Type: application/x-sentry-envelope" \
--data-binary @fixtures/sentry/browser/envelope.txt
Endpoints that matter
We can present a table or list. Use markdown table.
| Method | Path |
|---|---|
| POST | /api/{project_id}/store/ |
| POST | /api/{project_id}/envelope/ |
| GET | /health |
When 202 is a lie
Paragraph: 202 means auth + schema accepted. It is non-blocking. It does not mean “row visible in Issues yet.”
Checklist when the feed stays empty after a 202
List:
- Wait, then refresh - accept is ahead of the worker. One immediate refresh is not final.
- Environment chip - UI filter must match environment in Sentry.init ( local in the examples).
- Project / DSN mismatch - open the project that owns the key you put in dsn .
- Wrong host or port - EPURE_PUBLIC_URL / EPURE_PORT drift after a .env change without recreating the app container.
- SDK still talking to SaaS - leftover dsn , or a second Sentry.init later in boot.
- If store curl returns 202 but the SDK path does not, debug the client.
- If both miss 202 , debug the host ( docker compose logs on the app service, health, DSN key).
What this host is not
Paragraph: Exception-only lane. Do not expect APM, session replay, profiling, log product, or mobile SDKs to “just work” because the DSN looks familiar. JS/TS source maps are a separate verify step (upload + prove demangled frames) - out of scope here. Do not write “100% Sentry compatible” in a PR description or a README badge. Honest subset: official SDK, DSN swap, exceptions, envelope/store.
FAQ
List:
- Does Sentry JS 8.x work? Often yes. CI fixtures are 7.120.0 . On v8+, set enableTracing: false when the option exists, and keep traces / profiles / replay sample rates at 0 . Pin 7.120.0 if you want the same line the docs exercise. Confirm with a real throw, not only a green install.
- Can I use Python or curl only? Yes. Envelope and store accept official Sentry SDKs and raw JSON. Store is the smallest wire path. Phase 1 demangle stays JS/TS only, so frames stay as sent for other runtimes.
- Do I need Redis? No. Two containers for this path: app + Postgres 16. Laptop compose in production? No. Use the production overlay and a real .env from .env.production.example . Seed script and example DB passwords are local smoke only.
Canonical docs
List:
- Quickstart (this flow): https://epure.sh/docs/get-started/quickstart
- Install / Postgres 16 / prod overlay: https://epure.sh/docs/self-hosting/installation
If those URLs 404 someday, the commands above still stand: health JSON, store/envelope 202 , DSN host swap, sample rates at 0 .
Discussion
Paragraph: After ingest returns 202 but Issues stays empty - do you check the environment chip, project/DSN match, or worker lag first?
Then after that, we have the duplicate block again. So we repeat the same sections again exactly
Comments
No comments yet. Start the discussion.