Quickstart
Send your first trace to Maple in about five minutes, from your own stack or with a single curl request.
You need a Maple account and either an app to instrument or a terminal with curl.
1. Sign up and pick a region
Sign up at app.maple.dev. During onboarding you pick the region your organization lives in, US or EU. The region cannot be changed later, and each region has its own ingest endpoint:
| Region | Ingest endpoint |
|---|---|
| United States | https://ingest.maple.dev |
| European Union | https://ingest.eu.maple.dev |
2. Copy your ingest key
Open Settings → Ingestion and copy the private key (maple_sk_…). It is for servers and scripts. The public key (maple_pk_…) is for browser code. Both can only send telemetry. See Authentication.
3. Set the exporter variables
Every OpenTelemetry SDK reads these standard variables:
export OTEL_EXPORTER_OTLP_ENDPOINT="https://ingest.maple.dev" # EU: https://ingest.eu.maple.dev
export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_INGEST_KEY"
export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
export OTEL_SERVICE_NAME="quickstart"
The endpoint is the base URL. Exporters append /v1/traces, /v1/logs and /v1/metrics themselves.
4. Send a trace
Pick your stack. Each setup reads the variables from step 3, so run it in the same shell.
Install the auto-instrumentations package and start your app through its register entry point. No code changes:
npm install @opentelemetry/api @opentelemetry/auto-instrumentations-node
node --require @opentelemetry/auto-instrumentations-node/register app.jsSend a request to your app. Each incoming HTTP request becomes a trace, with child spans for outgoing calls and database queries. For ES module apps and the full setup with logs and metrics, see the Node.js guide.
Install @vercel/otel:
npm install @vercel/otel @opentelemetry/apipnpm add @vercel/otel @opentelemetry/apibun add @vercel/otel @opentelemetry/apiCreate instrumentation.ts in the project root (or src/instrumentation.ts if your code lives in src/). With no exporter passed, @vercel/otel reads the endpoint and headers from the variables:
// instrumentation.ts
import { registerOTel } from "@vercel/otel"
export function register() {
registerOTel({ serviceName: "quickstart" })
}Start the dev server with npm run dev and open a page. Each request becomes a trace with spans for rendering, route handlers and server fetch() calls. On Next.js 13.4 and 14, enable the instrumentation hook first; see the Next.js guide, which also covers logs and metrics.
Install the distro and the HTTP exporter, then let opentelemetry-bootstrap add the instrumentation packages for the libraries you already use:
pip install opentelemetry-distro opentelemetry-exporter-otlp-proto-http
opentelemetry-bootstrap -a installStart your app through the opentelemetry-instrument wrapper. No code changes:
opentelemetry-instrument python app.py
# or: opentelemetry-instrument uvicorn main:appSend a request to your app. FastAPI, Django, Flask and the common HTTP and database clients are traced automatically. Keep OTEL_EXPORTER_OTLP_PROTOCOL from step 3: the distro defaults to gRPC, which Maple does not accept. The wrapper does not work with uvicorn --reload. For logs, metrics and a setup in code, see the Python guide.
Go has no zero-code agent, so add the SDK and wrap your HTTP handler:
go get go.opentelemetry.io/otel \
go.opentelemetry.io/otel/sdk \
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp \
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttppackage main
import (
"context"
"log"
"net/http"
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
sdktrace "go.opentelemetry.io/otel/sdk/trace"
)
func main() {
ctx := context.Background()
// Reads OTEL_EXPORTER_OTLP_ENDPOINT and OTEL_EXPORTER_OTLP_HEADERS.
// A setup error only disables tracing; it never stops the app.
if exporter, err := otlptracehttp.New(ctx); err != nil {
log.Printf("telemetry disabled: %v", err)
} else {
tp := sdktrace.NewTracerProvider(sdktrace.WithBatcher(exporter))
defer tp.Shutdown(ctx)
otel.SetTracerProvider(tp)
}
mux := http.NewServeMux()
mux.HandleFunc("GET /hello", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello"))
})
log.Fatal(http.ListenAndServe(":8080", otelhttp.NewHandler(mux, "server")))
}Run it with go run . and call curl localhost:8080/hello. Each request becomes a server span, named after OTEL_SERVICE_NAME. For logs, metrics, gRPC and database/sql, see the Go guide.
Download the OpenTelemetry Java agent and attach it when you start your app. No code changes:
curl -L -o opentelemetry-javaagent.jar \
https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar
java -javaagent:opentelemetry-javaagent.jar -jar app.jarSend a request to your app. The agent instruments Spring, servlet containers, JDBC, HTTP clients and most other popular libraries, and exports traces, metrics and logs. It works the same for Kotlin and any other JVM app. See the Java guide or the Kotlin guide.
Add the hosting extension, the OTLP exporter and ASP.NET Core instrumentation:
dotnet add package OpenTelemetry.Extensions.Hosting
dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol
dotnet add package OpenTelemetry.Instrumentation.AspNetCoreRegister OpenTelemetry in Program.cs. UseOtlpExporter() reads the endpoint, protocol and headers from the variables:
using OpenTelemetry;
using OpenTelemetry.Trace;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddOpenTelemetry()
.WithTracing(tracing => tracing.AddAspNetCoreInstrumentation())
.UseOtlpExporter();
var app = builder.Build();
app.MapGet("/", () => "Hello!");
app.Run();Start it with dotnet run and send a request. Each request becomes a server span. For HttpClient, Entity Framework, logs and metrics, see the .NET guide.
Install the Laravel OpenTelemetry package:
composer require keepsuit/laravel-opentelemetryLaravel reads its configuration from .env, so put the values from step 3 there instead of exporting them:
# .env
OTEL_SERVICE_NAME=quickstart
OTEL_EXPORTER_OTLP_ENDPOINT=https://ingest.maple.dev
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_HEADERS="Authorization=Bearer YOUR_INGEST_KEY"Send a request to your app. Each request becomes a trace with spans for database queries, Redis commands and Http facade calls. If protobuf export fails in your environment, set OTEL_EXPORTER_OTLP_PROTOCOL=http/json. For queues, logs and metrics, see the Laravel guide.
Install Maple’s Effect SDK:
npm install @maple-dev/effect-sdk effectpnpm add @maple-dev/effect-sdk effectbun add @maple-dev/effect-sdk effectThe SDK takes the key from MAPLE_INGEST_KEY rather than the OTLP headers variable, and uses OTEL_EXPORTER_OTLP_ENDPOINT from step 3 for the region:
export MAPLE_INGEST_KEY="YOUR_INGEST_KEY"Provide the layer to your program:
import { Maple } from "@maple-dev/effect-sdk"
import { Effect } from "effect"
const program = Effect.gen(function* () {
yield* Effect.log("Hello from Effect!")
}).pipe(Effect.withSpan("hello-maple"))
Effect.runPromise(program.pipe(Effect.provide(Maple.layer({ serviceName: "quickstart" }))))Run it once. The hello-maple span and its log line reach Maple together. For Effect 3, browsers and Cloudflare Workers, see the Effect SDK.
To check the key and endpoint before touching your app, post one span as OTLP JSON. No SDK needed:
NOW=$(date +%s)
curl -i "${OTEL_EXPORTER_OTLP_ENDPOINT}/v1/traces" \
-H "Authorization: Bearer YOUR_INGEST_KEY" \
-H "Content-Type: application/json" \
-d '{
"resourceSpans": [{
"resource": { "attributes": [{ "key": "service.name", "value": { "stringValue": "quickstart" } }] },
"scopeSpans": [{
"spans": [{
"traceId": "5b8efff798038103d269b633813fc60c",
"spanId": "eee19b7ec3c1b174",
"name": "GET /hello",
"kind": 2,
"startTimeUnixNano": "'"${NOW}"'000000000",
"endTimeUnixNano": "'"${NOW}"'250000000",
"status": { "code": 1 }
}]
}]
}]
}'A 200 response means Maple accepted the span. Change the traceId to send another trace with the same command.
Rust, Kotlin and other stacks have their own guides under Instrument your application. The variables from step 3 stay the same.
5. Verify
Open Explore → Traces and filter Service to quickstart (or your OTEL_SERVICE_NAME). The trace appears within about a minute. Click it to see its spans.
Troubleshooting
401from the ingest endpoint. The key is wrong, or it belongs to the other region. A US key is rejected byingest.eu.maple.devand the other way around. See Regions.- Nothing shows up. Maple accepts OTLP over HTTP only. An exporter set to
grpcor pointed at port4317cannot reach it; usehttp/protobufand the endpoint without a port. SetOTEL_LOG_LEVEL=debugto print export errors. - The trace is there, but under a name like
unknown_service.OTEL_SERVICE_NAMEwas not set in the shell (or.env) that started the app, so the SDK fell back to a defaultservice.name. - Still nothing. Check the time range on the Traces page. For the curl span, your machine’s clock sets the timestamp.
More status codes and their meaning are in the Ingest API reference.
Next steps
- Instrument your application: full guides per language, with logs and metrics.
- Traces: search, filter and open traces.
- Service map: see calls between services once two of them are instrumented.
- Alert rules: get notified when error rate or latency crosses a threshold.