LLM Guides

Named Entity Recognition with JavaScript and LLMAPI

Aug 05, 2026

Messy text is where useful data goes to hide.

A customer mentions a company name in the middle of a support rant. A sales call transcript includes three people, two dates, one competitor, and a budget number nobody added to the CRM. A legal note has organizations, addresses, case names, dates, and contract terms scattered across ten paragraphs. A resume contains skills, employers, universities, locations, job titles, and dates, all formatted like the writer had a personal war with consistency.

That is where Named Entity Recognition helps.

Named Entity Recognition, or NER, turns text like this:

Maria Chen from BrightCart emailed Acme Logistics on July 14 about the delayed Chicago shipment.

into structured data like this:

{
  "people": ["Maria Chen"],
  "organizations": ["BrightCart", "Acme Logistics"],
  "dates": ["July 14"],
  "locations": ["Chicago"]
}

Much nicer.

This guide shows how to do Named Entity Recognition with JavaScript using LLMAPI, so messy text can become cleaner structured data. We’ll also look at top tools for NER, how they work, when to use LLMAPI instead of a classic NER API, and the best practices that keep your extraction pipeline from turning into a beautiful JSON hallucination machine.

What is Named Entity Recognition?

Named Entity Recognition is an NLP task that finds named things in text and classifies them into categories.

Common entity types include:

Entity typeExample
PersonMaria Chen
OrganizationAcme Logistics
LocationChicago
DateJuly 14, 2026
Money$12,500
ProductSalesforce
EventBlack Friday
Job titleHead of Operations
SkillPython
Email[email protected]
Phone number+1 312 555 0182
URLhttps://example.com

Classic NER tools usually focus on common categories like people, organizations, locations, dates, and money. LLM-based extraction can go further and pull custom entities like:

customer pain point
contract obligation
software feature
compliance risk
recipe ingredient
sales objection
job requirement

That flexibility is the fun part.

It is also the part where validation becomes very important.

Why NER matters in real apps

NER helps your app turn unstructured text into something searchable, sortable, filterable, and automatable.

For example, NER can help with:

  1. CRM enrichment.
  2. Support ticket routing.
  3. Contract analysis.
  4. Resume parsing.
  5. Invoice and receipt processing.
  6. News monitoring.
  7. Medical text extraction.
  8. Legal document review.
  9. Customer feedback analysis.
  10. Knowledge graph building.
  11. Search indexing.
  12. Compliance workflows.

Without NER, your app sees this:

“John from Northwind asked if the Zurich contract renewal could move to Sept 3.”

With NER, your app sees this:

{
  "person": "John",
  "organization": "Northwind",
  "location": "Zurich",
  "date": "Sept 3",
  "event_or_action": "contract renewal"
}

That structured layer makes the text usable.

Why we can write this guide

We’ve spent around 6 years working with AI APIs, NLP workflows, document parsing, structured extraction, embeddings, LLM-based automation, and JavaScript backend integrations. We also checked current docs for LLMAPI, Google Cloud Natural Language, Amazon Comprehend, Azure AI Language, spaCy, and recent NER research while preparing this guide.

The research direction is pretty clear: NER is no longer only a classic “tag words in a sentence” task. Modern systems mix rule-based extraction, statistical models, transformers, domain-specific models, and LLMs depending on the data and accuracy needs. A 2025 review of NER in Artificial Intelligence Review covers the field from learning methods to modeling paradigms and tasks. A 2026 paper on NERLLM argues for hybrid NER setups that combine local NER models with LLM reasoning, which is very close to how practical production systems are moving.

Translation for builders: use the tool that matches the job. Classic NER is fast and predictable. LLM-based NER is flexible and better for custom schemas. A strong product may use both.

What does “NER with JavaScript and LLMAPI” mean?

In this article, JavaScript is the backend language and LLMAPI is the model gateway.

The workflow looks like this:

text
→ JavaScript backend
→ LLMAPI extraction prompt
→ structured JSON
→ validation
→ app/database/workflow

Example:

“Please follow up with Anna Petrova at Stripe about the $8,000 invoice due next Friday.”

Output:

{
  "people": [
    {
      "name": "Anna Petrova",
      "role": null
    }
  ],
  "organizations": [
    {
      "name": "Stripe"
    }
  ],
  "money": [
    {
      "amount": 8000,
      "currency": "USD",
      "raw_text": "$8,000"
    }
  ],
  "dates": [
    {
      "raw_text": "next Friday",
      "normalized": null
    }
  ],
  "actions": [
    {
      "type": "follow_up",
      "description": "Follow up about the invoice"
    }
  ]
}

The important part is that LLMAPI can extract entities based on your schema, not only a fixed set of built-in labels.

That is useful when your app has its own entity types.

Classic NER vs LLM-based NER

Both approaches are useful.

ApproachBest forWatch out for
Classic NER modelFast extraction of common entitiesLimited custom categories
Rule-based extractionEmails, phone numbers, IDs, dates, SKUsBrittle with messy text
Cloud NER APIStable entity extraction at scaleProvider-specific categories
LLM-based NERCustom entities and flexible schemasNeeds validation and guardrails
Hybrid NERProduction workflows with quality controlMore setup and evaluation

A practical setup often looks like this:

regex/rules for obvious things
+ NER API for common entities
+ LLMAPI for custom entities and reasoning
+ validation before saving

That mix gives you better control than asking one model to do everything.

Top tools for NER workflows

Here are the tools worth knowing.

ToolBest for
LLMAPICustom entity extraction, schema-based JSON, summaries, routing
Google Cloud Natural LanguageCloud entity analysis and salience
Amazon ComprehendAWS-native entity detection and custom entities
Azure AI LanguageMicrosoft/Azure NER and custom NER workflows
spaCyLocal open-source NER and custom pipelines
compromiseLightweight JavaScript NLP
winkNLPFast JavaScript NLP pipelines
Transformers.jsRunning transformer models in JavaScript
Regex/rulesEmails, phone numbers, URLs, IDs, SKUs
Vector search + LLMAPIEntity linking and knowledge-base enrichment

Now let’s look at how these fit.

1. LLMAPI for custom structured extraction

LLMAPI is the best fit when your entity schema is custom, flexible, or business-specific.

Classic NER can find:

person, organization, location, date

LLMAPI can extract:

customer complaint, requested action, renewal risk, competitor mention, product feature, pricing objection

The LLMAPI quick-start docs show an OpenAI-compatible chat completions pattern using the /v1/chat/completions style endpoint. That means you can use OpenAI-compatible JavaScript clients and keep your backend integration fairly simple.

Good fits for LLMAPI NER:

  1. Support ticket extraction.
  2. CRM notes.
  3. Sales calls.
  4. Legal clauses.
  5. Resume fields.
  6. Product feedback.
  7. Research notes.
  8. Healthcare-adjacent admin text with proper compliance review.
  9. Procurement documents.
  10. Internal knowledge base cleanup.

Example output for a support ticket:

{
  "customer": {
    "name": "Jordan Lee",
    "company": "Northstar Labs"
  },
  "issue": {
    "type": "billing",
    "summary": "Customer says they were charged twice"
  },
  "dates": [
    {
      "raw_text": "last Thursday",
      "normalized": null
    }
  ],
  "money": [
    {
      "raw_text": "$299",
      "amount": 299,
      "currency": "USD"
    }
  ],
  "urgency": "high"
}

That is more useful than a plain list of entities.

2. Google Cloud Natural Language

Google Cloud Natural Language entity analysis can inspect text for known entities and return information like entity types, salience, mentions, and metadata. Google’s Natural Language API basics explain that the API can perform entity analysis and other text analysis methods, and the analyzeEntities reference documents the REST method.

Good fits:

  1. Google Cloud apps.
  2. News/content analysis.
  3. Search indexing.
  4. Entity salience scoring.
  5. Document tagging.
  6. Apps that already use Google Cloud Storage, BigQuery, or Cloud Functions.

How it works:

text
→ Google Cloud Natural Language
→ entities + type + salience + mentions
→ app stores tags/metadata

This is especially useful when you want entity salience, meaning which entities are more central to the text.

3. Amazon Comprehend

Amazon Comprehend is the AWS-native NLP service for entity detection, sentiment, key phrases, language detection, and custom classification/extraction. The Amazon Comprehend developer guide describes the service as using machine learning to find insights and relationships in text, and its entity detection operations can identify entities like people, places, organizations, quantities, dates, and more.

Good fits:

  1. AWS apps.
  2. S3 document pipelines.
  3. Lambda-based text processing.
  4. Support ticket analysis.
  5. Entity detection at scale.
  6. Custom entity recognition.
  7. Data lake enrichment.
  8. Enterprise text analytics.

How it works:

text / documents
→ Amazon Comprehend
→ detected entities
→ S3 / database / search index

Amazon Comprehend is convenient if your documents already live in S3 and your processing pipeline already uses AWS.

4. Azure AI Language

Azure AI Language named entity recognition can identify entities in text and categorize them. Azure also supports custom named entity recognition, which lets teams build domain-specific extraction models.

Good fits:

  1. Microsoft/Azure apps.
  2. Enterprise document workflows.
  3. Custom NER projects.
  4. Customer support analysis.
  5. Legal or internal text extraction with governance.
  6. Teams using Azure AI Foundry or Azure Functions.

How it works:

text
→ Azure AI Language NER
→ entities and categories
→ optional custom NER
→ app workflow

Azure is especially worth considering if your company already has Azure governance, identity, compliance, and security controls in place.

5. spaCy

spaCy is one of the most popular open-source NLP libraries for production-style pipelines. Its named entity recognition docs describe NER as assigning labels to contiguous spans of tokens, and its EntityRecognizer API documents the trainable ner pipeline component.

spaCy is Python-first, but it still fits JavaScript apps well when you expose it as a small internal service.

Workflow:

JavaScript backend
→ internal spaCy service
→ entities
→ JavaScript app continues workflow

Good fits:

  1. Local/private NER.
  2. Custom trained models.
  3. Offline processing.
  4. Internal document pipelines.
  5. Teams comfortable running Python microservices.
  6. Cases where data should not leave your infrastructure.

This is a nice hybrid option: JavaScript runs the app, spaCy handles local NER, LLMAPI handles custom reasoning or cleanup.

6. compromise

compromise is a lightweight JavaScript NLP library.

It can help with simpler entity-like extraction in Node.js or the browser, such as people, places, organizations, dates, and other grammatical patterns depending on the plugin/setup.

Good fits:

  1. Lightweight JavaScript apps.
  2. Quick prototypes.
  3. Browser-side text hints.
  4. Simple name/date extraction.
  5. Cases where you do not need heavy NLP infrastructure.

Example direction:

text
→ compromise
→ quick local entities
→ LLMAPI for cleanup/custom fields

Use compromise when you need something simple and fast inside JavaScript.

7. winkNLP

winkNLP is another JavaScript NLP library focused on fast text processing.

It can support tokenization, entity extraction patterns, and other NLP tasks depending on models and setup.

Good fits:

  1. JavaScript-only NLP.
  2. Fast local processing.
  3. Preprocessing before LLMAPI.
  4. Text cleaning and tokenization.
  5. Lightweight extraction.

A practical setup:

winkNLP preprocesses text
→ rules extract obvious entities
→ LLMAPI extracts custom schema
→ app validates result

This is useful when you want to reduce the amount of text sent to an LLM or clean it first.

8. Transformers.js

Transformers.js lets developers run transformer models in JavaScript. For NER, that can mean running token classification models in Node.js or even in the browser, depending on the model and environment.

Good fits:

  1. JavaScript ML experiments.
  2. Local model inference.
  3. Browser-based demos.
  4. Privacy-sensitive workflows where external API calls are limited.
  5. Lightweight custom model deployment.

Watch out for:

  1. Model size.
  2. Latency.
  3. Browser performance.
  4. Tokenization behavior.
  5. Accuracy on your domain.
  6. Maintenance.

This is a strong option if you want local inference in JavaScript, but cloud APIs are usually simpler for early production builds.

9. Regex and rules

Do not underestimate boring rules.

Regex is still great for entities that follow predictable patterns:

EntityExample
Email[email protected]
Phone+1 312 555 0144
URLhttps://example.com
ZIP code60632
Invoice IDINV-1042
Order IDORD-8831
SKUSKU-AB-2026
Currency$1,250.00

Example:

const emailRegex = /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi;

function extractEmails(text) {
  return [...text.matchAll(emailRegex)].map((match) => ({
    value: match[0],
    start: match.index,
    end: match.index + match[0].length
  }));
}

Use rules for obvious things.

Use LLMAPI for messy context.

10. Vector search plus LLMAPI for entity linking

NER finds entities.

Entity linking connects those entities to known records.

Example:

Apple

Could mean:

  1. Apple Inc.
  2. apple fruit.
  3. Apple Records.
  4. A project name inside your company.

Entity linking resolves that ambiguity.

A practical workflow:

extract entity
→ search knowledge base
→ retrieve candidate records
→ LLMAPI chooses or marks uncertain
→ save linked entity ID

Example:

{
  "entity": "Apple",
  "type": "organization",
  "linked_record": {
    "id": "org_apple_inc",
    "name": "Apple Inc."
  },
  "confidence": 0.87,
  "review_required": false
}

This is useful for CRMs, knowledge graphs, customer support, news analysis, and legal research.

A simple JavaScript + LLMAPI NER workflow

Here is the clean version.

POST /extract-entities
→ validate text
→ build extraction schema
→ call LLMAPI
→ parse JSON
→ validate schema
→ normalize entities
→ return result

Minimal JavaScript example:

import OpenAI from "openai";
import { z } from "zod";

const client = new OpenAI({
  apiKey: process.env.LLMAPI_API_KEY,
  baseURL: "https://api.llmapi.ai/v1"
});

const EntityExtractionSchema = z.object({
  people: z.array(z.string()).default([]),
  organizations: z.array(z.string()).default([]),
  locations: z.array(z.string()).default([]),
  dates: z.array(z.string()).default([]),
  money: z.array(z.string()).default([]),
  products: z.array(z.string()).default([])
});

async function extractEntities(text) {
  const response = await client.chat.completions.create({
    model: "gpt-4o-mini",
    messages: [
      {
        role: "system",
        content: `
Extract named entities from the text.
Return only valid JSON.
Use empty arrays when no entities are found.
Do not invent entities that are not present in the text.
        `
      },
      {
        role: "user",
        content: text
      }
    ],
    temperature: 0
  });

  const raw = response.choices[0].message.content;
  const parsed = JSON.parse(raw);

  return EntityExtractionSchema.parse(parsed);
}

That is enough for a simple prototype.

For production, you need better schemas, source spans, validation, and error handling.

Better output: include spans and evidence

A plain list is useful, but source spans are better.

Instead of:

{
  "organizations": ["Acme Logistics"]
}

return:

{
  "organizations": [
    {
      "value": "Acme Logistics",
      "start": 38,
      "end": 52,
      "evidence": "Acme Logistics",
      "confidence": "high"
    }
  ]
}

Why spans matter:

  1. The UI can highlight entities.
  2. Reviewers can verify extraction.
  3. You can avoid invented entities.
  4. You can debug model behavior.
  5. You can map entities back to source text.
  6. You can build audit trails.

A stronger schema:

const ExtractedEntitySchema = z.object({
  value: z.string(),
  type: z.enum([
    "person",
    "organization",
    "location",
    "date",
    "money",
    "product",
    "email",
    "phone",
    "url",
    "custom"
  ]),
  start: z.number().nullable(),
  end: z.number().nullable(),
  evidence: z.string(),
  confidence: z.enum(["low", "medium", "high"]),
  normalized_value: z.string().nullable(),
  review_required: z.boolean()
});

const NERResponseSchema = z.object({
  entities: z.array(ExtractedEntitySchema),
  warnings: z.array(z.string()).default([])
});

That gives your app much better output.

Example response for messy text

Input:

Hey, can you ask Daniel Rivera from Northwind to send the revised $14,500 proposal by Sept 12? Also loop in Maya from legal.

Output:

{
  "entities": [
    {
      "value": "Daniel Rivera",
      "type": "person",
      "start": 17,
      "end": 31,
      "evidence": "Daniel Rivera",
      "confidence": "high",
      "normalized_value": "Daniel Rivera",
      "review_required": false
    },
    {
      "value": "Northwind",
      "type": "organization",
      "start": 37,
      "end": 46,
      "evidence": "Northwind",
      "confidence": "high",
      "normalized_value": "Northwind",
      "review_required": false
    },
    {
      "value": "$14,500",
      "type": "money",
      "start": 67,
      "end": 74,
      "evidence": "$14,500",
      "confidence": "high",
      "normalized_value": "14500 USD",
      "review_required": false
    },
    {
      "value": "Sept 12",
      "type": "date",
      "start": 87,
      "end": 94,
      "evidence": "Sept 12",
      "confidence": "medium",
      "normalized_value": null,
      "review_required": true
    },
    {
      "value": "Maya",
      "type": "person",
      "start": 109,
      "end": 113,
      "evidence": "Maya",
      "confidence": "medium",
      "normalized_value": "Maya",
      "review_required": true
    }
  ],
  "warnings": [
    "The date 'Sept 12' has no year.",
    "The person 'Maya' has no last name."
  ]
}

Notice the review flags.

That is what makes the output practical.

Best practices for LLM-based NER

LLM-based NER is powerful, but you need guardrails.

Use a strict schema

Do not ask:

Find important entities.

Ask:

Extract entities using this JSON schema.
Use only the allowed entity types.
Use null when a field is missing.

Require evidence

Ask for the exact source phrase for each entity.

If the model cannot point to evidence, your backend should flag the entity.

Use empty arrays

Tell the model to return empty arrays when nothing is found.

That is cleaner than random prose like:

No entities found.

Validate with code

Use Zod, JSON Schema, or another validator.

The model generates. Your backend checks.

Keep temperature low

NER is an extraction task, so use low temperature.

temperature: 0

You want consistency, not creativity.

Add confidence and review flags

Let the system say:

{
  "confidence": "medium",
  "review_required": true
}

This helps with ambiguous names, missing dates, unclear organizations, and domain-specific terms.

Avoid over-extraction

Tell the model what to ignore.

Example:

Do not extract generic nouns unless they are part of a named entity.

Otherwise “customer,” “invoice,” and “proposal” may start showing up as fake entities.

Common NER problems

NER gets messy fast.

ProblemExampleFix
Ambiguous entityAppleUse entity linking
Partial nameMayaFlag for review
Missing yearSept 12Normalize only if reference date is known
Generic noun extractedproposalRestrict entity types
Duplicate entitiesIBM / International Business MachinesNormalize aliases
Nested entitiesUniversity of Chicago Medical CenterDecide span rules
Wrong typeJordan tagged as locationUse validation/review
Hallucinated entityModel invents companyRequire evidence span
Domain-specific entity“React” skill vs reactionUse custom schema/context
Multilingual textMixed English/Spanish namesDetect language and test

NER is not only extraction. It is cleanup.

Entity normalization

Raw entities are often not enough.

You may need normalized values.

Examples:

Raw entityNormalized value
Sept 122026-09-12
$1.2k1200 USD
NYCNew York City
IBMInternational Business Machines
[email protected][email protected]
next Friday2026-08-28, if reference date is known

Do not normalize dates like “next Friday” without a reference date.

Your app should pass one:

{
  "reference_date": "2026-08-21",
  "timezone": "America/Chicago"
}

Then LLMAPI can return:

{
  "raw_text": "next Friday",
  "normalized_value": "2026-08-28",
  "timezone": "America/Chicago"
}

This prevents date chaos.

Tiny detail. Big deal.

Entity deduplication

Text often repeats the same entity.

Example:

Acme said Acme Logistics will send the Acme invoice tomorrow.

You may extract Acme three times.

That can be useful if you need spans. But for CRM enrichment, you may want unique entities.

Return both:

{
  "mentions": [
    {
      "value": "Acme",
      "start": 0,
      "end": 4
    },
    {
      "value": "Acme Logistics",
      "start": 10,
      "end": 24
    }
  ],
  "unique_entities": [
    {
      "canonical_name": "Acme Logistics",
      "aliases": ["Acme"]
    }
  ]
}

Mentions help with highlighting.

Unique entities help with databases.

Entity linking

Entity linking connects extracted text to known records.

Example:

{
  "value": "Northwind",
  "type": "organization",
  "linked_id": "org_9821",
  "canonical_name": "Northwind Traders",
  "confidence": 0.91
}

Useful linking targets:

  1. CRM contacts.
  2. Companies.
  3. Products.
  4. SKUs.
  5. Locations.
  6. Knowledge base pages.
  7. Legal matters.
  8. Patient/customer records.
  9. Vendor records.
  10. Internal project IDs.

Workflow:

extract entity
→ search database
→ rank candidates
→ link if confidence is high
→ review if uncertain

This is where NER becomes actual automation.

NER for support tickets

Input:

Lisa from BrightCart says checkout failed twice yesterday and wants a refund for order BC-8821.

Useful extraction:

{
  "customer_name": "Lisa",
  "company": "BrightCart",
  "issue_type": "checkout_failure",
  "date": "yesterday",
  "requested_action": "refund",
  "order_id": "BC-8821"
}

Best practices:

  1. Extract order IDs with rules.
  2. Extract customer/company with NER.
  3. Extract issue type with LLMAPI.
  4. Route high-urgency or refund cases to review.
  5. Link company to CRM if possible.

Workflow:

ticket text
→ entities
→ issue type
→ urgency
→ route queue

NER for sales notes

Input:

Call with Priya at DataNest. They’re comparing us with Segment and want pricing before Q4 planning.

Useful extraction:

{
  "contact": "Priya",
  "account": "DataNest",
  "competitor": "Segment",
  "requested_info": "pricing",
  "timeline": "before Q4 planning"
}

This can update CRM fields automatically:

  1. Contact mentioned.
  2. Account mentioned.
  3. Competitor detected.
  4. Buying timeline found.
  5. Follow-up needed.

LLMAPI is helpful here because “pricing before Q4 planning” is not a standard classic NER category. It is business context.

NER for legal documents

Legal NER may need entities like:

  1. Parties.
  2. Effective dates.
  3. Governing law.
  4. Jurisdiction.
  5. Payment obligations.
  6. Termination dates.
  7. Notice addresses.
  8. Contract values.
  9. Clause references.
  10. Defined terms.

Classic NER can find people, organizations, dates, and locations.

LLMAPI can extract legal-specific fields if you provide a strict schema.

Example:

{
  "parties": [],
  "effective_date": null,
  "governing_law": null,
  "payment_obligations": [],
  "termination_rights": [],
  "notice_address": null,
  "missing_fields": []
}

Best practice: legal extraction should always include source quotes and review flags. Do not let a model silently summarize obligations without evidence.

NER for resumes

Resume parsing uses NER-style extraction all over the place.

Useful entities:

  1. Candidate name.
  2. Email.
  3. Phone.
  4. Location.
  5. Companies.
  6. Job titles.
  7. Skills.
  8. Degrees.
  9. Universities.
  10. Dates.
  11. Certifications.
  12. Tools and technologies.

Example schema:

{
  "candidate": {
    "name": null,
    "email": null,
    "phone": null,
    "location": null
  },
  "experience": [],
  "education": [],
  "skills": [],
  "certifications": []
}

For resumes, combine:

regex for email/phone
+ classic NER for names/orgs/locations
+ LLMAPI for structured resume sections
+ validation for dates and duplicates

That layered approach works better than relying on one extraction pass.

JavaScript endpoint shape

Here is a practical Express-style endpoint without turning the article into a code wall.

app.post("/extract-entities", async (req, res) => {
  const { text, schemaName, referenceDate } = req.body;

  if (!text || text.length < 5) {
    return res.status(400).json({
      error: "Text is required."
    });
  }

  const extraction = await extractEntitiesWithLLMAPI({
    text,
    schemaName,
    referenceDate
  });

  const validation = validateExtraction(extraction);

  if (!validation.valid) {
    return res.status(422).json({
      error: "Entity extraction failed validation.",
      details: validation.errors
    });
  }

  return res.json({
    status: "success",
    entities: extraction.entities,
    warnings: extraction.warnings || []
  });
});

The important pieces are:

  1. Validate input.
  2. Use the right schema.
  3. Extract with LLMAPI.
  4. Validate output.
  5. Return clean JSON.

That is the article in one endpoint.

Prompt pattern for LLMAPI NER

Use a prompt like this:

You extract named entities from text.

Rules:
- Return only valid JSON.
- Use only the entity types in the schema.
- Do not invent entities.
- Each entity must include an exact evidence phrase from the source text.
- Use null when a normalized value is unknown.
- Flag ambiguous entities with review_required: true.
- Do not extract generic nouns unless they are part of a named entity.

Then pass the schema:

{
  "entities": [
    {
      "value": "string",
      "type": "person | organization | location | date | money | product | email | phone | url | custom",
      "evidence": "string",
      "start": "number or null",
      "end": "number or null",
      "normalized_value": "string or null",
      "confidence": "low | medium | high",
      "review_required": "boolean"
    }
  ],
  "warnings": ["string"]
}

This gives the model less room to wander.

Validation checklist

After extraction, validate:

  • Is the output valid JSON?
  • Does it match the schema?
  • Are all entity types allowed?
  • Does every entity have evidence?
  • Does the evidence appear in the source text?
  • Are dates normalized only when enough context exists?
  • Are money fields parsed correctly?
  • Are emails and phone numbers valid?
  • Are duplicates handled?
  • Are uncertain entities flagged?
  • Are sensitive fields protected?
  • Are high-risk domains routed to review?

That checklist matters more than making the prompt longer.

Security and privacy best practices

NER often extracts personal data.

Names, emails, phone numbers, addresses, IDs, and workplace details may be sensitive.

Best practices:

  1. Keep API keys on the backend.
  2. Avoid logging raw sensitive text.
  3. Redact PII in logs.
  4. Store only needed entities.
  5. Encrypt sensitive extracted data.
  6. Add retention rules.
  7. Limit access to extraction results.
  8. Follow privacy requirements for your region/use case.
  9. Add review for medical, legal, HR, finance, and identity workflows.
  10. Let users delete or correct stored data when applicable.

A safe logging record:

{
  "request_id": "ner_123",
  "schema": "support_ticket_v2",
  "text_length": 842,
  "entity_count": 12,
  "review_required": true,
  "latency_ms": 920
}

Avoid logging:

{
  "raw_text": "Hi my name is..."
}

NER creates structured data. That makes it easier to use and easier to misuse.

Handle it carefully.

Evaluation: how to know if your NER works

Do not judge NER by a few sample sentences.

Build a small test set from real examples.

Track:

MetricWhat it tells you
PrecisionHow many extracted entities are correct
RecallHow many real entities were found
F1 scoreBalance of precision and recall
Type accuracyWhether entities get the right category
Span accuracyWhether boundaries are correct
Normalization accuracyWhether dates/money/entities are cleaned correctly
False positivesExtra entities that should not be there
False negativesMissed entities
Review rateHow often humans need to check
Downstream usefulnessWhether the output helps the workflow

For LLM-based extraction, also track:

  1. JSON validity.
  2. Schema validity.
  3. Evidence validity.
  4. Hallucinated entity rate.
  5. Cost per extraction.
  6. Latency.
  7. Retry/fallback rate.

A pretty response is useless if it invents entities.

Common mistakes

MistakeBetter approach
Asking for “important entities”Define exact entity types
No schema validationValidate with Zod or JSON Schema
No source evidenceRequire exact evidence text
No review flagsMark ambiguous entities
Treating all NER as the sameUse domain-specific schemas
Extracting generic nounsRestrict to named or useful fields
No entity linkingConnect entities to known records
No deduplicationKeep mentions and unique entities separately
Logging raw PIIRedact logs
Using only LLMs for emails/phonesUse regex/rules for obvious patterns
Ignoring date contextPass reference date and timezone
Saving uncertain data as truthAdd confidence and review states

The biggest mistake is treating extraction as a final answer.

Extraction is a first pass. Your backend still needs validation, normalization, and review logic.

Where LLMAPI fits best

LLMAPI fits best when your NER workflow needs one of these:

  1. Custom entity types.
  2. Structured JSON.
  3. Domain-specific extraction.
  4. Human-readable review notes.
  5. Routing decisions.
  6. Entity cleanup.
  7. Entity normalization.
  8. Summaries from extracted entities.
  9. Multi-step extraction workflows.
  10. Fallback between models.

Example workflow:

support ticket
→ rules extract email/order ID
→ LLMAPI extracts issue, company, date, requested action
→ backend validates schema
→ CRM/contact linking
→ route ticket

Another workflow:

contract text
→ LLMAPI extracts parties/dates/obligations
→ source evidence check
→ legal review queue

LLMAPI gives you flexibility. Your backend gives you discipline.

That combination is the whole point.

A simple production workflow

Here is the version we would actually ship:

text enters app
→ validate length and language
→ extract obvious patterns with rules
→ run classic NER or cloud NER for common entities
→ use LLMAPI for custom schema extraction
→ validate JSON
→ check source evidence
→ normalize dates/money/entities
→ deduplicate and link records
→ flag uncertain fields
→ save or route to review

For small apps, start simpler:

text
→ LLMAPI schema extraction
→ Zod validation
→ return entities

Then add rules, linking, and review as your use case grows.

The practical takeaway

You can do Named Entity Recognition with JavaScript and LLMAPI by building a backend that sends text to LLMAPI with a strict schema, receives structured JSON, validates the output, and returns clean entities to your app.

Use LLMAPI when you need custom entity types, business-specific extraction, review notes, routing, or structured JSON. Use Google Cloud Natural Language, Amazon Comprehend, or Azure AI Language when you want cloud NER services. Use spaCy when you want local/custom open-source NER. Use JavaScript tools like compromise, winkNLP, regex, or Transformers.js when you want lighter local extraction.

A strong workflow looks like this:

messy text
→ JavaScript backend
→ NER tools + LLMAPI
→ structured entities
→ validation
→ database/workflow

That is how messy text becomes cleaner structured data without pretending the first JSON response is automatically perfect.

Deploy in minutes