I have been working on some side projects and one functionality that I had to build more than one time is extracting Twitter and Facebook Open Graph meta tags information for a website (And I use C#).

I have a rule for myself. If I do something more than once, I want to create a library so that I don't have to redo the whole thing every time or copy paste stuff.

So I created a small library for doing this.

First, lets talk about social meta tags (but if you already know, you can skip ahead). When you go on Twitter or Facebook and you post a link to a website or blog post, you see a neat preview.

Twitter shows something like this:

Twitter URL Preview

While Facebook shows something like this:

Facebook URL preview

Twitter and Facebook uses certain meta tags to get this information. So when you are developing an app where you want to extract some basic information of a URL, you can also look for these tags.

How to extract Twitter and Facebook Open Graph meta tags from a URL using C#?

We will create a small library for this. You can find the complete solution here and you can also use it in your project. If you are using it for commercial use, make sure you check for HtmlAgilityPack license since we will be using the library for loading HTML data.

  1. Open Visual Studio and create a new library project. I always use netstandard2.0 when I create a library.
Create .NET Standard library

2. Right click on Dependencies -> Manage NuGet packages -> Browse. Search for HtmlAgilityPack and install the package. I'm installing version v1.11.23. Alternatively, you can also edit the .csproj file and add the following reference.

<ItemGroup>
    <PackageReference Include="HtmlAgilityPack" Version="1.11.23" />
</ItemGroup>

3. Now we will create a class that will be our final return value. Create a new class file called SocialTags.cs. This will have both Twitter and Facebook data.

public class SocialTags
{
    public Twitter Twitter { get; }
    public Facebook Facebook { get; }

    public SocialTags(Twitter twitter, Facebook facebook)
    {
        Twitter = twitter;
        Facebook = facebook;
    }

}

4. Now let us define how Twitter and Facebook class will look like. But before we do that, we want to read both Twitter's and Facebook's documentation of the tags they use.

You can find them here: Twitter's documention and Facebook's documentation.

5. Let us create Twitter.cs and Facebook.cs members based on their documentation. I've mostly covered all the different tags I look for. But you can add them similarly if I have missed any.

public class Twitter
{
    public string Card { get; }
    public string Site { get; }
    public string SiteId { get; }
    public string Creator { get; }
    public string CreatorId { get; }
    public string Description { get; }
    public string Title { get; }
    public string Image { get; }
    public string ImageAlt { get; }
    public string Player { get; }
    public string PlayerWidth { get; }
    public string PlayerHeight { get; }
    public string PlayerStream { get; }
    public string AppNameIPhone { get; }
    public string AppIdIPhone { get; }
    public string AppUrlIPhone { get; }
    public string AppNameIPad { get; }
    public string AppIdIPad { get; }
    public string AppUrlIPad { get; }
    public string AppNameGooglePlay { get; }
    public string AppIdGooglePlay { get; }
    public string AppUrlGooglePlay { get; }
}
public class Facebook
{
    public string Url { get; }
    public string Title { get; }
    public string SiteName { get; }
    public string Description { get; }
    public string Image { get; }
    public string ImageType { get; }
    public string ImageHeight { get; }
    public string ImageWidth { get; }
    public string AppId { get; }
    public string Type { get; }
    public string Locale { get; }
}

6. Now let us create the class that will have the logic to make a request to the URL and return the output. Create a file called SocialMetaTags.cs. We want to define a method that returns SocialTags.

public class SocialMediaTags
{
    public async Task<SocialTags> Tags(string url)
    {
        
    }
}

7. We installed HtmlAgilityPack, it is time to use it.

private static HtmlWeb client = new HtmlWeb();
public async Task<SocialTags> Tags(string url)
{
    var html = await client.LoadFromWebAsync(url);
    var metaTags = html.DocumentNode.SelectNodes("//meta");
}

In first line, we are making an async request to load HTML data for the input URL.

In the next line, we are getting the meta tag nodes. HtmlAgilityPack returns HtmlNodeCollection in the second line.

8. We defined the members of Twitter and Facebook with private set, so let us create constructors for Twitter and Facebook class which accepts HtmlNodeCollection as input.

public Twitter(HtmlNodeCollection metaTags)
{
}

public Facebook(HtmlNodeCollection metaTags)
{
}

9. Now that we have our inputs, let us read the value for each tag based on the documentation above from Twitter and Facebook. For this, we will iterate through each node in HtmlNodeCollection, check for the property mentioned in the documentation and if it matches, we will get the corresponding content value.

With those changes, our final Twitter.cs file will look like this:

public class Twitter
{
    public string Card { get; }
    public string Site { get; }
    public string SiteId { get; }
    public string Creator { get; }
    public string CreatorId { get; }
    public string Description { get; }
    public string Title { get; }
    public string Image { get; }
    public string ImageAlt { get; }
    public string Player { get; }
    public string PlayerWidth { get; }
    public string PlayerHeight { get; }
    public string PlayerStream { get; }
    public string AppNameIPhone { get; }
    public string AppIdIPhone { get; }
    public string AppUrlIPhone { get; }
    public string AppNameIPad { get; }
    public string AppIdIPad { get; }
    public string AppUrlIPad { get; }
    public string AppNameGooglePlay { get; }
    public string AppIdGooglePlay { get; }
    public string AppUrlGooglePlay { get; }


    public Twitter(HtmlNodeCollection metaTags)
    {
        foreach (var tag in metaTags)
        {
            var content = tag.Attributes["content"];
            var property = tag.Attributes["property"];
            if (property != null)
            {
                switch (property.Value.ToLower())
                {
                    case "twitter:card":
                        Card = content.Value;
                        break;
                    case "twitter:site":
                        Site = content.Value;
                        break;
                    case "twitter:creator":
                        Creator = content.Value;
                        break;
                    case "twitter:creator:id":
                        CreatorId = content.Value;
                        break;
                    case "twitter:description":
                        Description = content.Value;
                        break;
                    case "twitter:title":
                        Title = content.Value;
                        break;
                    case "twitter:image":
                        Image = content.Value;
                        break;
                    case "twitter:image:alt":
                        ImageAlt = content.Value;
                        break;
                    case "twitter:player":
                        Player = content.Value;
                        break;
                    case "twitter:player:width":
                        PlayerWidth = content.Value;
                        break;
                    case "twitter:player:height":
                        PlayerHeight = content.Value;
                        break;
                    case "twitter:player:stream":
                        PlayerStream = content.Value;
                        break;
                    case "twitter:app:name:iphone":
                        AppNameIPhone = content.Value;
                        break;
                    case "twitter:app:id:iphone":
                        AppIdIPhone = content.Value;
                        break;
                    case "twitter:app:url:iphone":
                        AppUrlIPhone = content.Value;
                        break;
                    case "twitter:app:name:ipad":
                        AppNameIPad = content.Value;
                        break;
                    case "twitter:app:id:ipad":
                        AppIdIPad = content.Value;
                        break;
                    case "twitter:app:url:ipad":
                        AppUrlIPad = content.Value;
                        break;
                    case "twitter:app:name:googleplay":
                        AppNameGooglePlay = content.Value;
                        break;
                    case "twitter:app:id:googleplay":
                        AppIdGooglePlay = content.Value;
                        break;
                    case "twitter:app:url:googleplay":
                        AppUrlGooglePlay = content.Value;
                        break;
                }
            }
        }
    }
}

And our Facebook.cs file will look like this:

public class Facebook
{
    public string Url { get; }
    public string Title { get; }
    public string SiteName { get; }
    public string Description { get; }
    public string Image { get; }
    public string ImageType { get; }
    public string ImageHeight { get; }
    public string ImageWidth { get; }
    public string AppId { get; }
    public string Type { get; }
    public string Locale { get; }

    public Facebook(HtmlNodeCollection metaTags)
    {
        foreach (var tag in metaTags)
        {
            var content = tag.Attributes["content"];
            var property = tag.Attributes["property"];
            if (property != null)
            {
                switch (property.Value.ToLower())
                {
                    case "og:url":
                        Url = content.Value;
                        break;
                    case "og:title":
                        Title = content.Value;
                        break;
                    case "og:site_name":
                        SiteName = content.Value;
                        break;
                    case "og:description":
                        Description = content.Value;
                        break;
                    case "og:image":
                        Image = content.Value;
                        break;
                    case "og:image:type":
                        ImageType = content.Value;
                        break;
                    case "og:image:width":
                        ImageWidth = content.Value;
                        break;
                    case "og:image:height":
                        ImageHeight = content.Value;
                        break;
                    case "fb:app_id":
                        AppId = content.Value;
                        break;
                    case "og:type":
                        Type = content.Value;
                        break;
                    case "og:locale":
                        Locale = content.Value;
                        break;
                }
            }
        }
    }
}

10. We have our logics in place to read the HtmlNodeCollection and create Twitter and Facebook objects. The next step is to create these objects from SocialMetaTags.cs file and return the data. So our final SocialMetaTags.cs file will look like this:

public class SocialMediaTags
{
    private static HtmlWeb client = new HtmlWeb();
    public async Task<SocialTags> Tags(string url)
    {
        var html = await client.LoadFromWebAsync(url);
        var metaTags = html.DocumentNode.SelectNodes("//meta");
        var twitter = new Twitter(metaTags);
        var facebook = new Facebook(metaTags);
        var socialTags = new SocialTags(twitter: twitter, facebook: facebook);

        return socialTags;
    }
}

That's it. Now you can call this method passing it a URL and get Twitter and Facebook Open Graph meta tags information.

You can see the final code here: SocialMetaTags using C#.