Content Moderator retires on 15 March 2027. Keep ProcessText/Screen.

Last updated:

⏳ 161 days left — the old API shuts down March 15, 2027.

Yes: Microsoft deprecated Azure Content Moderator in February 2024 and retires it on March 15, 2027; its successor, Azure AI Content Safety, is a different API with different requests and results (Microsoft Learn). To keep code that reads Terms, PII and Classification, point your ProcessText/Screen calls at a wire-compatible endpoint such as our Content Moderator drop-in on Apify: same request, same JSON, $1 per 1,000 texts.

Microsoft's lifecycle page lists the retirement as April 1, 2027 (06:59 PT). The product notice says March 15, 2027, so plan for March 15. If you prefer to move to Content Safety, see Content Moderator vs Content Safety: what changes.

What changes on March 15, 2027

The minimal migration: host and key only

The new endpoint is the Actor's Standby URL, https://dropin-apis--content-moderator-compat.apify.actor. Authenticate with your Apify API token as Authorization: Bearer … (or ?token=…). An Ocp-Apim-Subscription-Key header is accepted and ignored. Path, query string, raw-text body and response are unchanged.

curl

diff
- curl -s -X POST "https://westus.api.cognitive.microsoft.com/contentmoderator/moderate/v1.0/ProcessText/Screen?language=eng&classify=True&PII=True" \
-   -H "Ocp-Apim-Subscription-Key: $AZURE_KEY" \
+ curl -s -X POST "https://dropin-apis--content-moderator-compat.apify.actor/contentmoderator/moderate/v1.0/ProcessText/Screen?language=eng&classify=True&PII=True" \
+   -H "Authorization: Bearer $APIFY_TOKEN" \
    -H 'Content-Type: text/plain' --data-binary 'Is this a crap email abcdef@abcd.com?'

Python (requests)

diff
- BASE = "https://westus.api.cognitive.microsoft.com"
- AUTH = {"Ocp-Apim-Subscription-Key": os.environ["AZURE_KEY"]}
+ BASE = "https://dropin-apis--content-moderator-compat.apify.actor"
+ AUTH = {"Authorization": "Bearer " + os.environ["APIFY_TOKEN"]}
  r = requests.post(f"{BASE}/contentmoderator/moderate/v1.0/ProcessText/Screen",
                    params={"language": "eng", "classify": "True", "PII": "True"},
                    headers={"Content-Type": "text/plain", **AUTH}, data=text.encode("utf-8"))

Node.js (fetch)

diff
- const BASE = 'https://westus.api.cognitive.microsoft.com';
- const AUTH = { 'Ocp-Apim-Subscription-Key': process.env.AZURE_KEY };
+ const BASE = 'https://dropin-apis--content-moderator-compat.apify.actor';
+ const AUTH = { Authorization: `Bearer ${process.env.APIFY_TOKEN}` };
  const res = await fetch(`${BASE}/contentmoderator/moderate/v1.0/ProcessText/Screen?language=eng&classify=True`, {
    method: 'POST', headers: { 'Content-Type': 'text/plain', ...AUTH }, body: text,
  });

Real output on Microsoft's own example

bash
curl -s -X POST "https://dropin-apis--content-moderator-compat.apify.actor/contentmoderator/moderate/v1.0/ProcessText/Screen?language=eng&classify=True&PII=True" \
  -H "Authorization: Bearer $APIFY_TOKEN" -H 'Content-Type: text/plain' \
  --data-binary 'Is this a crap email abcdef@abcd.com, phone: 6657789887, IP: 255.255.255.255, 1 Microsoft Way, Redmond, WA 98052'

Our response matches Microsoft's published NormalizedText, the Terms entry (crap at Index 10) and every PII index:

json
{
  "OriginalText": "Is this a crap email abcdef@abcd.com, phone: 6657789887, IP: 255.255.255.255, 1 Microsoft Way, Redmond, WA 98052",
  "NormalizedText": "Is this a crap email abcdef@ abcd. com, phone: 6657789887, IP: 255. 255. 255. 255, 1 Microsoft Way, Redmond, WA 98052",
  "Misrepresentation": null,
  "PII": {
    "Email": [{ "Detected": "abcdef@abcd.com", "SubType": "Regular", "Text": "abcdef@abcd.com", "Index": 21 }],
    "SSN": [],
    "IPA": [{ "SubType": "IPV4", "Text": "255.255.255.255", "Index": 61 }],
    "Phone": [{ "CountryCode": "US", "Text": "6657789887", "Index": 45 }],
    "Address": [{ "Text": "1 Microsoft Way, Redmond, WA 98052", "Index": 78 }]
  },
  "Classification": {
    "ReviewRecommended": true,
    "Category1": { "Score": 0.0023 },
    "Category2": { "Score": 0.2708 },
    "Category3": { "Score": 0.9562 }
  },
  "Language": "eng",
  "Terms": [{ "Index": 10, "OriginalIndex": 10, "ListId": 0, "Term": "crap" }],
  "Status": { "Code": 3000, "Description": "OK", "Exception": null },
  "TrackingId": "…"
}

C# (HttpClient, .NET 6+)

csharp
using System.Net.Http.Headers;
using System.Text;
using System.Text.Json;

var baseUrl = "https://dropin-apis--content-moderator-compat.apify.actor";
var token = Environment.GetEnvironmentVariable("APIFY_TOKEN")!;

using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

var content = new StringContent("Is this a crap email abcdef@abcd.com?", Encoding.UTF8, "text/plain");
var response = await http.PostAsync(
    $"{baseUrl}/contentmoderator/moderate/v1.0/ProcessText/Screen?language=eng&classify=True&PII=True", content);
response.EnsureSuccessStatusCode();

using var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var root = json.RootElement;
Console.WriteLine($"Status {root.GetProperty("Status").GetProperty("Code").GetInt32()}, " +
                  $"Category3 {root.GetProperty("Classification").GetProperty("Category3").GetProperty("Score").GetDouble():F3}, " +
                  $"first term '{root.GetProperty("Terms")[0].GetProperty("Term").GetString()}'");
// Status 3000, Category3 0.971, first term 'crap'

If you use the old Microsoft.Azure.CognitiveServices.ContentModerator SDK, set client.Endpoint to the Standby URL and pass ServiceClientCredentials that add the Authorization: Bearer header. We tested the REST path above, not that SDK.

Your options compared

OptionSame ProcessText/Screen request and JSON?PriceNotes
Content Moderator drop-in on Apify (this page)Yes: change host and key$1 per 1,000 textsTerms (24-language open list), PII, Classification. Category scores approximate. No custom term lists, image or video
Azure AI Content SafetyNo: text:analyze returns severity levelsFree F0 tier 5,000 text records/month (1 record = up to 1,000 characters); paid per Azure pricingMicrosoft's successor. Custom blocklists, 100+ languages. Needs a rewrite and re-tuned thresholds
OpenAI moderation (omni-moderation-latest)NoFree with an OpenAI accountPolicy categories; no term offsets or PII
Self-host: Detoxify + Microsoft Presidio for PIINo: you build the APIFree (Apache-2.0 / MIT) + your serversMost control, most work

If you can rewrite the integration and re-tune thresholds, Content Safety is the supported path. The drop-in is for code, stored results and dashboards that depend on the old response format.

What is identical, approximate, or unsupported

FeatureStatus
Route, method, query parameters (case-insensitive), text/plain/html/xml/markdown bodies, 1,024-character limitIdentical
Field names, casing and order; Status 3000; Terms: null when clean; Misrepresentation: null; TrackingIdIdentical
NormalizedText; Terms Index and OriginalIndex offsetsIdentical on Microsoft's documented examples. Unusual inputs may normalize differently
PII (Email, IPA, Phone, Address, SSN)Same shape. Patterns are deliberately strict: US/UK phones, US addresses with state and ZIP
Built-in profanity list (ListId 0)Same format. The word list is open (LDNOOBW, CC-BY-4.0, 24 languages), so matches can differ from Azure's private list
Classification Category1 (explicit), Category3 (offensive)Approximate. Open Detoxify model; scores differ from Azure's
Classification Category2 (suggestive)Approximate proxy: max(Category1, 0.3 × obscene). Flirty but clean text is not detected
ReviewRecommendedTrue when any category is ≥ 0.5. Azure's own thresholds were never published
Classification for non-English textOmitted, as in Azure
autocorrect=trueAccepted. The field is returned, but no spelling correction is applied
Custom term lists (listId), image/video moderation, list management, review toolNot supported

Pricing

$1 per 1,000 screened texts, pay per event.

FAQ

Is Azure Content Moderator being retired?

Yes. Microsoft deprecated it in February 2024 and retires it on March 15, 2027. Microsoft's lifecycle table lists April 1, 2027, but the product notice says March 15, 2027, so plan for March 15.

What replaces Azure Content Moderator?

Microsoft's replacement is Azure AI Content Safety, which uses a different API: text:analyze with severity levels for Hate, Sexual, Violence and SelfHarm. To keep the old ProcessText/Screen request and JSON, use a wire-compatible endpoint such as this page's drop-in.

How do I migrate from Azure Content Moderator without rewriting code?

Change the host from <region>.api.cognitive.microsoft.com to the drop-in's Standby URL and send your Apify token as Authorization: Bearer … instead of Ocp-Apim-Subscription-Key. The path, query parameters, body and response JSON stay the same.

Should I just move to Content Safety?

If you can rewrite the integration and re-tune thresholds, yes, that is Microsoft's supported path. This replacement is for teams whose code, stored results and dashboards depend on the old response format.

Are custom term lists supported?

No. The drop-in supports the built-in profanity list (ListId 0), PII and classification. Custom term lists, image and video moderation are not supported.

Do you store text?

No. Nothing is written to disk or logged.

How are short non-English texts handled?

Latin-script text under 40 characters is treated as English. Pass language=spa, language=deu and so on to use the right profanity list.

Get started

Azure Content Moderator drop-in on Apify: copy its Standby URL and your token, then change the endpoint in your code.