---
title: "Named entity recognition in C#"
url: https://recursiveai.org/onenlp/cookbook/named-entity-recognition/
description: "Find names of people and places with OneNLP’s packaged English model."
version: "1.0.0"
---

# Named entity recognition in C#

**OneNLP** is a free, open-source natural language processing library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneNlp) · [GitHub](https://github.com/recursive-ai-oss/onenlp-csharp) · [Docs](https://recursiveai.org/onenlp/docs/) · [Download example (.zip)](https://recursiveai.org/onenlp/cookbook/named-entity-recognition/named-entity-recognition.zip)

Find names of people and places with OneNLP’s packaged English model.

```shell
dotnet add package RecursiveAI.OneNlp
dotnet add package RecursiveAI.OneNlp.Models.English
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using RecursiveAI.OneNlp;

var entities = Nlp.Entities(
    "Angela Merkel visited Paris.");
foreach (var entity in entities)
    Console.WriteLine(
        $"{entity.Text}: {entity.Label}");
```

The snippet prints each detected name and its label.

```text
Angela Merkel: PER
Paris: LOC
```

`PER` means person, `LOC` location, `ORG` organization and `MISC` miscellaneous (where the model’s training data includes that label).

Unzip [the example](https://recursiveai.org/onenlp/cookbook/named-entity-recognition/named-entity-recognition.zip), then `dotnet run`.

## The full program

The download’s `Program.cs` uses the same visible input as the snippet at the top. No input files are needed.

The download’s `Program.cs` is the snippet above.

`dotnet run` prints:

```text
Angela Merkel: PER
Paris: LOC
```

If the required language model is missing, `ModelNotAvailableException` names the package to add; nothing is downloaded.

## Variations

**Keep character offsets.** The explicit language overload skips language detection; offsets locate the names in the original string. This is a standalone replacement for `Program.cs`.

```csharp
using RecursiveAI.OneNlp;

var entities = Nlp.Entities("Angela Merkel visited Paris.", Language.English);
foreach (var entity in entities)
    Console.WriteLine($"{entity.StartChar}..{entity.EndChar}: {entity.Text}");
```

```text
0..13: Angela Merkel
22..27: Paris
```

## Related recipes

- [Detect the language of text in C#](https://recursiveai.org/onenlp/cookbook/language-detection/)
- [Tokenize text in C#](https://recursiveai.org/onenlp/cookbook/tokenize-text/)
- [Split text into sentences in C#](https://recursiveai.org/onenlp/cookbook/split-sentences/)
- [Lemmatize text in C#](https://recursiveai.org/onenlp/cookbook/lemmatize-text/)

---

## The short answer

Add the core package and `RecursiveAI.OneNlp.Models.English`, then call `Nlp.Entities(text)`. Each returned span has its text, label and character offsets. In the example, `Angela Merkel` is labeled `PER` and `Paris` is labeled `LOC`. The English model runs locally; it comes with its NuGet package rather than being downloaded on first use.

## How do I use named entity recognition in C#?

Use the complete program above as a starting point. Its input is an ordinary sentence, not a pretokenized array. The [model package documentation](https://recursiveai.org/onenlp/docs/model-packages/) explains how a package registers a pipeline for the high-level API. Adding the English package is sufficient; the application does not need to load a separate weights file.

The result is a list of spans in text order without overlaps. `Text` is the original substring, not a canonical name or database identifier. A span recognizing “Paris” does not tell you which municipality is intended, and recognizing a person does not resolve that person to a contact record. Keep those application decisions separate from extraction.

The variation prints `StartChar` and `EndChar`. The end is exclusive, so the name occupies the range from the start up to, but not including, the end. Use character offsets when highlighting names in the original string; `Start` and `End` instead address tokens. Preserve the string unchanged while consuming those offsets. Normalizing or editing it afterward can invalidate the positions.

The high-level API can detect the input language. When the language is already known, the explicit `Language.English` overload avoids that choice. This matters for short names or brief messages where the text contains little language evidence. The explicit overload still needs the corresponding model package.

## What is a named entity recognition model?

It is the trained component that predicts which token sequences are names and assigns their types. OneNLP’s [fast-tier documentation](https://recursiveai.org/onenlp/docs/fast-tier/) describes the pipeline’s `EntityRecognizer` and the entity labels from its training data: `PER`, `ORG`, `LOC`, and `MISC` where the data contains it. A model does not necessarily find every name, and different text domains can produce different mistakes. Check representative sentences from your own data, including ambiguous names and sentences with no entities.

A missing language model is not the same as an empty result. An empty list means the model returned no entities. A missing package raises `ModelNotAvailableException`, with a message naming what to add. By contrast, `Nlp.Analyze` can return tokens and sentence boundaries without model annotations when a language package is absent; don’t interpret that fallback as successful entity extraction.

For custom types, the library documents a separate open-type entity path and its required multilingual model. It isn’t enabled by adding a new label to this English example. Choose the model and API for the types you need, and keep its deployment requirements separate from this small person/place example.
