Advanced Claude
Best Practices & Safety
Build reliable, safe, and cost-effective applications with the Claude API.
Production Best Practices
Error Handling
Always wrap API calls in try-catch. The API can return:
400— Invalid request (bad parameters)401— Authentication error (invalid API key)403— Permission denied429— Rate limit exceeded500— Internal server error (retry with backoff)
Retry Logic
Implement exponential backoff for 429 and 500 errors.
Cost Optimization
- Use the cheapest model that works for your task
- Cache responses where possible
- Monitor token usage with
response.usage - Use
max_tokensto limit output length - Be concise in your system prompts
Security
- Never expose your API key in client-side code
- Always validate/sanitize user input before sending to Claude
- Use server-side API calls (Next.js API routes, Edge Functions)
- Implement rate limiting on your own endpoints
Safety & Responsible Use
Claude has built-in safety features, but you should:
- Monitor responses for inappropriate content
- Implement feedback mechanisms
- Test edge cases and adversarial inputs
- Follow Anthropic's usage policies
Example
typescript
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
// Robust wrapper with retry logic
async function callClaude(
messages: Anthropic.MessageParam[],
retries = 3
): Promise<string> {
for (let attempt = 1; attempt <= retries; attempt++) {
try {
const response = await client.messages.create({
model: "claude-haiku-3-5", // cheapest model
max_tokens: 1024,
messages,
});
return response.content[0].type === "text"
? response.content[0].text
: "";
} catch (error) {
if (error instanceof Anthropic.RateLimitError) {
if (attempt === retries) throw error;
// Exponential backoff: 1s, 2s, 4s
await new Promise(r => setTimeout(r, 1000 * 2 ** (attempt - 1)));
continue;
}
if (error instanceof Anthropic.APIError) {
console.error(`API Error ${error.status}: ${error.message}`);
}
throw error;
}
}
throw new Error("Max retries exceeded");
}
// Simple input validation
function sanitizeUserInput(input: string): string {
return input
.slice(0, 10000) // limit length
.replace(/<[^>]*>/g, "") // strip HTML
.trim();
}
// Cost tracking
const COSTS = {
"claude-haiku-3-5": { input: 0.0008, output: 0.004 },
"claude-opus-4-5": { input: 0.003, output: 0.015 },
};
function estimateCost(model: string, usage: Anthropic.Usage): number {
const rates = COSTS[model as keyof typeof COSTS];
if (!rates) return 0;
return (
(usage.input_tokens / 1000) * rates.input +
(usage.output_tokens / 1000) * rates.output
);
}Try it yourself — TYPESCRIPT