FlareLog SDK - Browser Guide
Quick Start (3 lines)
typescript
import { flarelog } from "@flarelog/sdk";
const logger = flarelog({ apiKey: "fl_your_api_key", });
logger.info("Page loaded", { url: window.location.href });The flarelog() factory auto-detects environment and enables console/globalErrors/rejections capture by default.
Vanilla JavaScript
html
<script type="module">
import { flarelog } from "@flarelog/sdk";
const logger = flarelog({
apiKey: "fl_your_api_key",
autoCapture: {
console: true,
globalErrors: true,
rejections: true,
// Note: http, navigation, and clicks capture is not yet implemented
},
});
// Set user context if authenticated
logger.setUser({
id: "user_123",
email: "user@example.com",
});
// Manual logging
logger.info("Page loaded", { url: window.location.href });
</script>React
typescript
// flarelog.ts
import { flarelog } from "@flarelog/sdk";
export const logger = flarelog({
apiKey: process.env.REACT_APP_FLARELOG_API_KEY!,
release: process.env.REACT_APP_VERSION,
autoCapture: {
console: true,
globalErrors: true,
rejections: true,
// Note: http, navigation, and clicks capture is not yet implemented
},
beforeSend: (log) => {
if (log.metadata?.password) delete log.metadata.password;
if (log.metadata?.token) log.metadata.token = "[REDACTED]";
return log;
},
});
// App.tsx
import { FlareLogErrorBoundary } from "@flarelog/sdk/react";
function App() {
return (
<FlareLogErrorBoundary logger={logger}>
<Router>
<Routes />
</Router>
</FlareLogErrorBoundary>
);
}
// Component.tsx
import { useFlareLog } from "@flarelog/sdk/react";
function MyComponent() {
const { trackEvent, trackError } = useFlareLog(logger);
const handleClick = () => {
trackEvent("button_clicked", { button: "checkout" });
};
return <button onClick={handleClick}>Click me</button>;
}typescript
// hooks/useUserTracking.ts
import { useEffect } from "react";
import { logger } from "../flarelog";
export function useUserTracking(user: { id: string; email: string } | null) {
useEffect(() => {
if (user) {
logger.setUser({
id: user.id,
email: user.email,
});
} else {
logger.setUser(null);
}
}, [user]);
}
// App.tsx
import { useUserTracking } from "./hooks/useUserTracking";
import { useAuth } from "./hooks/useAuth";
function App() {
const { user } = useAuth();
useUserTracking(user);
return (
<div>
{/* Your app */}
</div>
);
}typescript
// hooks/usePageView.ts
import { useFlareLogPageView } from "@flarelog/sdk/react";
import { logger } from "../flarelog";
export function usePageView(pageName?: string) {
useFlareLogPageView(logger, pageName);
}
// HomePage.tsx
import { usePageView } from "../hooks/usePageView";
export function HomePage() {
usePageView("Home");
return <div>Home</div>;
}React Error Boundary
typescript
// components/ErrorBoundary.tsx
import React from "react";
import { logger } from "../flarelog";
interface Props {
children: React.ReactNode;
fallback?: React.ReactNode;
}
interface State {
hasError: boolean;
error?: Error;
}
export class ErrorBoundary extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError(error: Error): State {
return { hasError: true, error };
}
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
logger.logError(error, {
message: "React error boundary caught error",
metadata: {
componentStack: errorInfo.componentStack,
reactVersion: React.version,
},
});
}
render() {
if (this.state.hasError) {
return this.props.fallback || (
<div className="error-fallback">
<h1>Something went wrong</h1>
<button onClick={() => window.location.reload()}>
Reload Page
</button>
</div>
);
}
return this.props.children;
}
}
// Usage in App.tsx
import { ErrorBoundary } from "./components/ErrorBoundary";
function App() {
return (
<ErrorBoundary fallback={<ErrorPage />}>
<Router>
<Routes />
</Router>
</ErrorBoundary>
);
}Vue 3
typescript
// plugins/flarelog.ts
import { flarelog } from "@flarelog/sdk";
const logger = flarelog({
apiKey: import.meta.env.VITE_FLARELOG_API_KEY,
environment: import.meta.env.MODE,
autoCapture: {
console: true,
globalErrors: true,
rejections: true,
// Note: http, navigation, and clicks capture is not yet implemented
},
});
export default {
install(app) {
app.config.globalProperties.$logger = logger;
// Vue error handler
app.config.errorHandler = (err, instance, info) => {
logger.logError(err, {
message: "Vue error",
metadata: {
component: instance?.$options?.name || "anonymous",
info,
},
});
};
// Vue warning handler
app.config.warnHandler = (msg, instance, trace) => {
logger.warn(msg, {
component: instance?.$options?.name,
trace,
});
};
},
};
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import flarelogPlugin from "./plugins/flarelog";
const app = createApp(App);
app.use(flarelogPlugin);
app.mount("#app");
// Usage in components
<script setup>
import { getCurrentInstance } from "vue";
const { proxy } = getCurrentInstance();
function handleClick() {
proxy.$logger.info("Button clicked", { button: "submit" });
}
</script>Next.js
For server-side routes use @flarelog/sdk/next. For client-side React components use @flarelog/sdk/react.
typescript
// lib/flarelog-client.ts (client-side logger)
import { flarelog } from "@flarelog/sdk";
export const clientLogger = flarelog({
apiKey: process.env.NEXT_PUBLIC_FLARELOG_API_KEY,
environment: process.env.NODE_ENV,
release: process.env.VERCEL_GIT_COMMIT_SHA || "dev",
serverName: "browser",
autoCapture: {
console: true,
globalErrors: true,
rejections: true,
// Note: http, navigation, and clicks capture is not yet implemented
},
beforeSend: (log) => {
// Scrub sensitive data
if (log.metadata?.password) delete log.metadata.password;
if (log.metadata?.creditCard) delete log.metadata.creditCard;
return log;
},
});
// pages/_app.tsx (Pages Router application shell)
import type { AppProps } from "next/app";
import { useEffect } from "react";
import { clientLogger } from "../lib/flarelog-client";
export default function MyApp({ Component, pageProps }: AppProps) {
useEffect(() => {
// Track page views
clientLogger.info("Page view", {
path: window.location.pathname,
referrer: document.referrer,
});
}, []);
return <Component {...pageProps} />;
}
// app/layout.tsx (App Router application shell)
"use client";
import { FlareLogErrorBoundary } from "@flarelog/sdk/react";
import { clientLogger } from "../lib/flarelog-client";
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html>
<body>
<FlareLogErrorBoundary logger={clientLogger}>
{children}
</FlareLogErrorBoundary>
</body>
</html>
);
}
// API Routes (pages/api/hello.ts)
import { flarelog } from "@flarelog/sdk";
import { withFlareLog } from "@flarelog/sdk/next";
const logger = flarelog({ apiKey: process.env.FLARELOG_API_KEY });
export default withFlareLog(logger, async (req, res) => {
req.logger.info("API request", { method: req.method, path: req.url });
const data = await fetchData();
res.status(200).json(data);
});
// App Router Route Handler (app/api/hello/route.ts)
import { flarelog } from "@flarelog/sdk";
import { withNextRouteHandler } from "@flarelog/sdk/next";
const logger = flarelog({ apiKey: process.env.FLARELOG_API_KEY });
export const GET = withNextRouteHandler(logger, async (request) => {
return Response.json({ message: "Hello from App Router!" });
});For App Router setup, Edge Middleware, and W3C trace propagation, see the dedicated Next.js guide.
Svelte / SvelteKit
typescript
// lib/flarelog.ts
import { flarelog } from "@flarelog/sdk";
export const logger = flarelog({
apiKey: import.meta.env.VITE_FLARELOG_API_KEY,
environment: import.meta.env.MODE,
autoCapture: {
console: true,
globalErrors: true,
rejections: true,
},
});
// hooks.client.ts (SvelteKit)
import { logger } from "$lib/flarelog";
export async function handleError({ error, event }) {
logger.logError(error, {
message: "SvelteKit client error",
metadata: {
url: event.url.pathname,
route: event.route?.id,
},
});
}
// hooks.server.ts (SvelteKit)
import { logger } from "$lib/flarelog";
export async function handleError({ error, event }) {
logger.logError(error, {
message: "SvelteKit server error",
metadata: {
url: event.url.pathname,
method: event.request.method,
},
});
}
// Usage in components
<script>
import { logger } from "$lib/flarelog";
function handleClick() {
logger.info("Button clicked", { button: "primary" });
}
</script>
<button on:click={handleClick}>Click me</button>Performance Tracking
typescript
// Track Web Vitals
import { getCLS, getFID, getFCP, getLCP, getTTFB } from "web-vitals";
import { logger } from "./flarelog";
function sendToFlareLog(metric) {
logger.info(`Web Vital: ${metric.name}`, {
value: metric.value,
rating: metric.rating, // 'good' | 'needs-improvement' | 'poor'
delta: metric.delta,
id: metric.id,
});
}
getCLS(sendToFlareLog);
getFID(sendToFlareLog);
getFCP(sendToFlareLog);
getLCP(sendToFlareLog);
getTTFB(sendToFlareLog);User Tracking
typescript
// Track user actions
function trackUserAction(action: string, data?: Record<string, unknown>) {
logger.addBreadcrumb({
category: "user",
message: action,
data,
});
logger.info(`User action: ${action}`, data);
}
// Track navigation
window.addEventListener("popstate", () => {
logger.addBreadcrumb({
category: "navigation",
message: `Navigated to ${window.location.pathname}`,
});
});
// Track form submissions
document.querySelectorAll("form").forEach(form => {
form.addEventListener("submit", (e) => {
logger.info("Form submitted", {
formId: form.id,
formAction: form.action,
});
});
});Redux / State Management
typescript
// middleware/flarelogMiddleware.ts
import { logger } from "../flarelog";
export const flarelogMiddleware = (store) => (next) => (action) => {
logger.addBreadcrumb({
category: "redux",
message: action.type,
data: { payload: action.payload },
});
try {
return next(action);
} catch (err) {
logger.logError(err, {
message: "Redux error",
metadata: {
action: action.type,
state: store.getState(),
},
});
throw err;
}
};
// store.ts
import { configureStore } from "@reduxjs/toolkit";
import { flarelogMiddleware } from "./middleware/flarelogMiddleware";
export const store = configureStore({
reducer: rootReducer,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware().concat(flarelogMiddleware),
});BeforeSend Examples
typescript
// Scrub PII
const logger = flarelog({
beforeSend: (log) => {
// Remove sensitive fields
const scrubbed = { ...log };
if (scrubbed.metadata) {
const sensitiveFields = [
"password", "token", "secret", "creditCard", "ssn",
"email", "phone", "address"
];
sensitiveFields.forEach(field => {
if (scrubbed.metadata[field]) {
scrubbed.metadata[field] = "[REDACTED]";
}
});
}
return scrubbed;
},
});
// Filter out health checks
const logger = flarelog({
beforeSend: (log) => {
if (log.message?.includes("/health")) {
return false; // Drop health check logs
}
return log;
},
});
// Add custom metadata
const logger = flarelog({
beforeSend: (log) => ({
...log,
metadata: {
...log.metadata,
appVersion: "1.2.3",
buildTime: BUILD_TIME,
},
}),
});Best Practices
- Initialize early: Create logger before app mounts
- Use environment variables: Don't hardcode API keys
- Enable autoCapture: Capture console, errors, and rejections
- Set user context: Identify users when they log in
- Add breadcrumbs: Track user actions before errors
- Use beforeSend: Scrub PII and filter noise
- Track releases: Tag logs with version for regression tracking
- Flush on unload: Ensure logs are sent before page closes
typescript
// Best-effort flush before page unload
// flush() returns a Promise; browsers may terminate before it resolves.
window.addEventListener("beforeunload", () => {
logger.flush();
});