Recursive AI

Extract contact information from HTML in C#

OneContact is a free, open-source contact data library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies, no network access.

Read the contact details a page states as person and organization records. It reads contact details in plain HTML and in marked-up formats such as hCard and schema.org. Pass in HTML you already have; this example does not fetch a page or run JavaScript.

Terminal
dotnet add package RecursiveAI.OneContact.Extraction

Requires .NET 10 (net10.0); .NET 9 and earlier aren’t supported.

C#
using RecursiveAI.OneContact.Extraction;
 
string html = """
<div class="vcard">
<b class="fn">Ada Example</b>
<a class="email">ada@example.com</a>
</div>
""";
var contacts = ContactExtractor.Extract(html);
foreach (var contact in contacts)
{
    Console.WriteLine(contact.Name?.Text);
    foreach (var email in contact.Emails)
        Console.WriteLine(email.Text);
}
Text
Ada Example
ada@example.com

Unzip the example, then dotnet run.

Full program

The download includes a fuller example with invented input embedded in Program.cs:

C#
using RecursiveAI.OneContact.Extraction;
 
string html = """
<div itemscope itemtype="https://schema.org/Person">
  <span itemprop="name">Ada Example</span>
  <a itemprop="email" href="mailto:ada@example.com">ada@example.com</a>
</div>
""";
foreach (var contact in ContactExtractor.Extract(html))
{
    Console.WriteLine(contact.Name?.Text);
    foreach (var email in contact.Emails)
        Console.WriteLine(email.Text);
}

dotnet run prints:

Text
Ada Example
ada@example.com

Oversized input can throw ContactExtractionException; markup problems that can be recovered from appear in the detailed result’s Issues.

Variations

Restrict extraction to structured markup:

C#
using RecursiveAI.OneContact.Extraction;
 
string html = """
<div itemscope itemtype="https://schema.org/Organization">
  <span itemprop="name">Example Workshop</span>
  <a itemprop="url" href="https://example.com">Website</a>
</div>
""";
var extractor = new ContactExtractor
{
    Sources = ExtractionSources.Markup
};
var result = extractor.ExtractHtml(html);
foreach (var contact in result.Records)
    Console.WriteLine(contact.Name?.Text);
Text
Example Workshop

The short answer

Use ContactExtractor.Extract(html) from the RecursiveAI.OneContact.Extraction package. It returns contact records rather than a list of strings that happen to resemble email addresses. A record can hold a name, phones, emails, websites and postal addresses. In the example above, itemprop ties the email to the named person, so the full program prints the name and email together.

The example HTML is invented and embedded in Program.cs; no sample download or account is needed. Replace the string with HTML your application already holds. The extractor reads that content, not a live browser window. It neither loads linked pages nor stores a copy of the content. See the extraction documentation for the result types and supported readers.

How do I extract contact information from HTML in C#?

Start with a contact record when the relationship between fields matters. The extractor reads JSON-LD, Microdata, RDFa and hCard markup, along with contact links and address elements. Its visible-text readers also find contact values the page states. A named property in markup provides stronger evidence of what a value means than an arbitrary string in a paragraph.

The full program uses Microdata: itemscope opens a record, the schema type identifies a person, and each itemprop identifies a field. The email link supplies both a displayed value and a mailto: target. The returned Name is optional, which is why the program uses ?.Text. A contact may have several emails; iterate the collection rather than taking its first element and silently losing the rest.

For diagnostics, use an extractor instance and ExtractHtml, as in the variation. Its detailed result exposes all Fields, Ungrouped values and Issues, not just Records. A value the page states but that cannot be normalized remains visible with its issue information. That distinction matters when deciding whether to import a field automatically or ask a person to review it.

What doesn’t contact extraction read from HTML?

Contact extraction is narrower than converting an entire document to plain text. The visible-text path looks for contact details; it does not promise to return all prose, preserve paragraph layout or reproduce what a script-driven browser displays. If your input contains only scripts that later construct the contact panel, obtain the resulting HTML before passing it to this API.

Choose ExtractionSources.Markup when your import contract is specifically about declared structured data. Keep the default readers when you also want contact details in visible text. The variation makes the choice explicit and prints the organization’s declared name.

Do not treat every field found on a page as belonging to one person. The detailed result distinguishes grouped records from ungrouped fields and preserves disagreements instead of choosing a winner. Review those signals before making a directory entry or sending mail. Successful extraction means the page stated a value; it is not evidence that an inbox receives messages, that a phone is active or that the named person consented to your intended use.

All onecontact recipes