Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Analyze text and images for harmful content using Azure AI Content Safety (@azure-rest/ai-content-safety). Use when moderating user-generated content, detecting hate speech, violence, sexual content, or self-harm, or managing custom blocklists.
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 56% | 0% |
| case-01 | ✗→✓ | ▲ Improved | 107% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 131% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 68% | 0% |
| case-09 | ✗→✓ | ▲ Improved | 88% | 0% |
Analyze text and images for harmful content with customizable blocklists.
bashnpm install @azure-rest/ai-content-safety @azure/identity @azure/core-auth
bashCONTENT_SAFETY_ENDPOINT=https://<resource>.cognitiveservices.azure.com CONTENT_SAFETY_KEY=<api-key> AZURE_TOKEN_CREDENTIALS=prod # Required only if DefaultAzureCredential is used in production
Important: This is a REST client. ContentSafetyClient is a function, not a class.
typescriptimport ContentSafetyClient from "@azure-rest/ai-content-safety"; import { AzureKeyCredential } from "@azure/core-auth"; const client = ContentSafetyClient( process.env.CONTENT_SAFETY_ENDPOINT!, new AzureKeyCredential(process.env.CONTENT_SAFETY_KEY!) );
typescriptimport ContentSafetyClient from "@azure-rest/ai-content-safety"; import { DefaultAzureCredential, ManagedIdentityCredential } from "@azure/identity"; // Local dev: DefaultAzureCredential. Production: set AZURE_TOKEN_CREDENTIALS=prod or AZURE_TOKEN_CREDENTIALS=<specific_credential> const credential = new DefaultAzureCredential({requiredEnvVars: ["AZURE_TOKEN_CREDENTIALS"]}); // Or use a specific credential directly in production: // See https://learn.microsoft.com/javascript/api/overview/azure/identity-readme?view=azure-node-latest#credential-classes // const credential = new ManagedIdentityCredential(); const client = ContentSafetyClient( process.env.CONTENT_SAFETY_ENDPOINT!, credential );
typescriptimport ContentSafetyClient, { isUnexpected } from "@azure-rest/ai-content-safety"; const result = await client.path("/text:analyze").post({ body: { text: "Text content to analyze", categories: ["Hate", "Sexual", "Violence", "SelfHarm"], outputType: "FourSeverityLevels" // or "EightSeverityLevels" } }); if (isUnexpected(result)) { throw result.body; } for (const analysis of result.body.categoriesAnalysis) { console.log(`${analysis.category}: severity ${analysis.severity}`); }
typescriptimport { readFileSync } from "node:fs"; const imageBuffer = readFileSync("./image.png"); const base64Image = imageBuffer.toString("base64"); const result = await client.path("/image:analyze").post({ body: { image: { content: base64Image } } }); if (isUnexpected(result)) { throw result.body; } for (const analysis of result.body.categoriesAnalysis) { console.log(`${analysis.category}: severity ${analysis.severity}`); }
typescriptconst result = await client.path("/image:analyze").post({ body: { image: { blobUrl: "https://storage.blob.core.windows.net/container/image.png" } } });
typescriptconst result = await client .path("/text/blocklists/{blocklistName}", "my-blocklist") .patch({ contentType: "application/merge-patch+json", body: { description: "Custom blocklist for prohibited terms" } }); if (isUnexpected(result)) { throw result.body; } console.log(`Created: ${result.body.blocklistName}`);
typescriptconst result = await client .path("/text/blocklists/{blocklistName}:addOrUpdateBlocklistItems", "my-blocklist") .post({ body: { blocklistItems: [ { text: "prohibited-term-1", description: "First blocked term" }, { text: "prohibited-term-2", description: "Second blocked term" } ] } }); if (isUnexpected(result)) { throw result.body; } for (const item of result.body.blocklistItems ?? []) { console.log(`Added: ${item.blocklistItemId}`); }
typescriptconst result = await client.path("/text:analyze").post({ body: { text: "Text that might contain blocked terms", blocklistNames: ["my-blocklist"], haltOnBlocklistHit: false } }); if (isUnexpected(result)) { throw result.body; } // Check blocklist matches if (result.body.blocklistsMatch) { for (const match of result.body.blocklistsMatch) { console.log(`Blocked: "${match.blocklistItemText}" from ${match.blocklistName}`); } }
typescriptconst result = await client.path("/text/blocklists").get(); if (isUnexpected(result)) { throw result.body; } for (const blocklist of result.body.value ?? []) { console.log(`${blocklist.blocklistName}: ${blocklist.description}`); }
typescriptawait client.path("/text/blocklists/{blocklistName}", "my-blocklist").delete();
| Category | API Term | Description | |----------|----------|-------------| | Hate and Fairness | Hate | Discriminatory language targeting identity groups | | Sexual | Sexual | Sexual content, nudity, pornography | | Violence | Violence | Physical harm, weapons, terrorism | | Self-Harm | SelfHarm | Self-injury, suicide, eating disorders |
| Level | Risk | Recommended Action | |-------|------|-------------------| | 0 | Safe | Allow | | 2 | Low | Review or allow with warning | | 4 | Medium | Block or require human review | | 6 | High | Block immediately |
Output Types:
FourSeverityLevels (default): Returns 0, 2, 4, 6EightSeverityLevels: Returns 0-7typescriptimport ContentSafetyClient, { isUnexpected, TextCategoriesAnalysisOutput } from "@azure-rest/ai-content-safety"; interface ModerationResult { isAllowed: boolean; flaggedCategories: string[]; maxSeverity: number; blocklistMatches: string[]; } async function moderateContent( client: ReturnType<typeof ContentSafetyClient>, text: string, maxAllowedSeverity = 2, blocklistNames: string[] = [] ): Promise<ModerationResult> { const result = await client.path("/text:analyze").post({ body: { text, blocklistNames, haltOnBlocklistHit: false } }); if (isUnexpected(result)) { throw result.body; } const flaggedCategories = result.body.categoriesAnalysis .filter(c => (c.severity ?? 0) > maxAllowedSeverity) .map(c => c.category!); const maxSeverity = Math.max( ...result.body.categoriesAnalysis.map(c => c.severity ?? 0) ); const blocklistMatches = (result.body.blocklistsMatch ?? []) .map(m => m.blocklistItemText!); return { isAllowed: flaggedCategories.length === 0 && blocklistMatches.length === 0, flaggedCategories, maxSeverity, blocklistMatches }; }
| Operation | Method | Path | |-----------|--------|------| | Analyze Text | POST | /text:analyze | | Analyze Image | POST | /image:analyze | | Create/Update Blocklist | PATCH | /text/blocklists/{blocklistName} | | List Blocklists | GET | /text/blocklists | | Delete Blocklist | DELETE | /text/blocklists/{blocklistName} | | Add Blocklist Items | POST | /text/blocklists/{blocklistName}:addOrUpdateBlocklistItems | | List Blocklist Items | GET | /text/blocklists/{blocklistName}/blocklistItems | | Remove Blocklist Items | POST | /text/blocklists/{blocklistName}:removeBlocklistItems |
typescriptimport ContentSafetyClient, { isUnexpected, AnalyzeTextParameters, AnalyzeImageParameters, TextCategoriesAnalysisOutput, ImageCategoriesAnalysisOutput, TextBlocklist, TextBlocklistItem } from "@azure-rest/ai-content-safety";
Other measured skills in the registry, with their headline benchmark lift.