Flutter OpenGraph Package

pub package pub points likes codecov Tests License: MIT

What is OpenGraph?

OpenGraph is a protocol that enables any web page to become a rich object in a social graph. It was originally created by Facebook to enable web pages to have the same functionality as other Facebook objects. Today, OpenGraph is used by most social media platforms, search engines, and messaging apps to create rich previews of shared links.

About This Package

The Flutter OpenGraph package provides a comprehensive solution for working with OpenGraph metadata in your Flutter applications. It offers dual functionality:

  1. OpengraphPreview Widget: A customizable Flutter widget that displays beautiful link previews using OpenGraph data from any URL
  2. opengraph_fetch: A powerful function that extracts OpenGraph metadata from URLs, supporting multiple formats

Key Features

  • Rich Link Previews: Transform plain URLs into engaging visual previews with title, description, and image
  • Multiple Metadata Formats: Support for OpenGraph, Twitter Cards, HTML meta tags, JSON-LD (including @graph) and favicon fallback
  • Rich Structured Data: Every og:image/og:video/og:audio object with width/height/alt, plus article:*/book:* tags
  • Customizable UI: Text styles, overlay color, image fit, tap callback and an alternative horizontal layout
  • Caching: Efficient memory caching with TTL expiration and in-flight request deduplication to avoid redundant network requests
  • Robust Fetching: URL normalization (www.example.com just works), controlled redirects with relative images resolved against the final URL, charset detection beyond UTF-8, configurable timeout, headers and CORS proxy
  • Direct API Access: Use the fetch API directly to get raw metadata for custom implementations
  • All Platforms: Pure package:http networking — works on Android, iOS, web, Windows, macOS and Linux
  • List-Friendly: Designed for scrollable lists — lazy fetch on viewport entry, memoized fetches, decode at display size, optional blur

Screenshots

OpenGraph Preview

Installation

Add the package to your pubspec.yaml file:

dependencies:
  opengraph: ^1.2.0

Then run:

flutter pub get

Getting Started

The package offers two main components that can be used independently or together:

1. OpengraphPreview Widget

This widget displays a rich preview of any URL, showing the title, description, and image extracted from the OpenGraph metadata.

2. opengraph_fetch Function

This function extracts OpenGraph metadata from a URL and returns it as a structured object, allowing you to use the data in your own custom UI.

Usage

No initialization is required: OpengraphPreview and opengraph_fetch work out of the box, with results cached in memory automatically.

Using the OpengraphPreview Widget

The widget allows you to preview OpenGraph data from a URL with various customization options:

OpengraphPreview(
  url: "https://www.youtube.com/watch?v=6g4dkBF5anU",
  height: 200,                           // Optional: Custom height for the preview
  borderRadius: 10,                      // Optional: Rounded corners radius
  backgroundColor: Colors.black87,       // Optional: Background color
  progressColor: Colors.white54,         // Optional: Loading indicator color
)

Customization Options

The OpengraphPreview widget supports the following customization options:

Parameter Type Description
url String The URL to fetch OpenGraph data from (required)
height double Height of the preview card (default: 200)
borderRadius double Radius for the card corners (default: 10)
backgroundColor Color Background color of the card (default: black87)
progressColor Color Color of the loading indicator (default: white54)
hideOnError bool Render nothing when the fetch fails (default: false)
childError Widget? Custom widget shown when the fetch fails, replaces the whole card
childPreview Widget? Custom widget shown while loading, instead of the progress indicator
showReloadButton bool Show a retry button on error that invalidates the cache (default: false)
refresh String Label of the retry button (default: "Refresh")
error String Message shown when the fetch fails
fallbackImage Widget? Custom widget shown when the page has no og:image, instead of the default image
enableBlur bool Blur effect behind the text overlay; disable in long lists for better performance (default: true)
titleStyle TextStyle? Merged over the default title style (white, bold)
descriptionStyle TextStyle? Merged over the default description style (white)
hostStyle TextStyle? Merged over the default host style (white54)
titleMaxLines int Maximum lines for the title (default: 1)
descriptionMaxLines int Maximum lines for the description (default: 2)
overlayColor Color Color of the panel behind the texts (default: 50% black)
imageFit BoxFit How the image fits its box (default: fitWidth)
onTap VoidCallback? Called when the loaded preview is tapped, e.g. to open the URL
layout OpenGraphLayout overlay (image with texts on top, default) or horizontal (side image + texts)
lazyLoad bool Defer the fetch until the widget is visible (default: false)
visibilityThreshold double Visible fraction that starts a lazy fetch (default: 0.1)

Caching

Fetched URLs are cached in memory, so scrolling through lists does not refetch. You can tune or bypass it:

OpengraphCache.maxEntries = 500;          // default: 200
OpengraphCache.ttl = const Duration(hours: 1); // default: 24h; null = session-long
OpengraphCache.evict("https://a.com");    // drop a single URL
OpengraphCache.clear();                   // drop everything
OpengraphCache.enabled = false;           // disable caching entirely

// Per-call freshness override:
await opengraph_fetch(url, maxAge: Duration.zero); // force a refetch

Network failures are not cached, so transient errors recover on the next attempt.

Network tuning

OpengraphFetch.timeout = const Duration(seconds: 5); // whole redirect chain
OpengraphFetch.maxRedirects = 3;                     // default: 7
OpengraphFetch.requestHeaders = {
  'User-Agent': 'MyApp/1.0',
};

// Per-call headers, merged over the defaults:
await opengraph_fetch(url, headers: {'Accept-Language': 'es'});

URLs without a scheme (www.example.com) are normalized to https:// before fetching, redirects are followed manually so relative images resolve against the destination URL, and non-UTF-8 pages (latin1, windows-1252…) are decoded from the charset declared in the response.

Flutter Web and CORS

On the web the browser enforces CORS, so most third-party sites refuse a direct fetch. Route the requests through a proxy with OpengraphFetch.proxyUrl — either a {url} template or a plain prefix that gets the encoded URL appended:

OpengraphFetch.proxyUrl = 'https://corsproxy.io/?url={url}';
// or
OpengraphFetch.proxyUrl = 'https://my-proxy.example.com/fetch?u=';

Relative images keep resolving against the target site, not the proxy. Note the browser also sets its own User-Agent, custom headers are subject to CORS preflight, and the preview images themselves still load from their original hosts.

Lazy loading in lists

With lazyLoad: true the fetch is deferred until the preview scrolls into the viewport, so a long list does not fire every request at once:

ListView.builder(
  itemBuilder: (context, index) => OpengraphPreview(
    url: urls[index],
    lazyLoad: true,
    enableBlur: false, // cheaper scrolling
  ),
)

Results land in the cache (with TTL), in-flight requests are deduplicated, and requests already started keep running to completion so the cache warms up even if the user scrolls past.

Rich metadata

OpenGraphEntity exposes the full structured protocol beyond the basic fields:

final entity = await opengraph_fetch("https://example.com/article");

entity!.images;          // List<OgImage>: every og:image with width/height/alt/secureUrl
entity.images.first.width;
entity.videos;           // List<OgVideo>: og:video objects
entity.audios;           // List<OgAudio>: og:audio objects
entity.structuredTags;   // article:*, book:*, profile:*, music:*, video:* tags
entity.structuredTags['article:tag']; // e.g. ["flutter", "opengraph"]
entity.faviconUrl;       // <link rel="icon"> resolved absolute, if any

When a page has no image in any metadata format, the favicon is used as a last-resort image, so previews still show something recognizable.

Styling Examples

Dark Theme:

OpengraphPreview(
  url: "https://flutter.dev",
  height: 200,
  borderRadius: 16,
  backgroundColor: Colors.black87,
  progressColor: Colors.white54,
)

Rounded Corners:

OpengraphPreview(
  url: "https://pub.dev/packages/opengraph",
  height: 180,
  borderRadius: 24,
  backgroundColor: Color(0xFFE0F7FA),
  progressColor: Colors.teal,
)

Using the opengraph_fetch Function

You can directly fetch OpenGraph metadata from any URL and use it in your own custom UI:

// Fetch OpenGraph data
final openGraphData = await opengraph_fetch("https://github.com/baldomerocho/flutter_opengraph");

// Access the structured data
print(openGraphData?.title);        // Title of the page
print(openGraphData?.description);  // Description of the page
print(openGraphData?.image);        // Featured image URL
print(openGraphData?.url);          // Canonical URL
print(openGraphData?.siteName);     // Site name
print(openGraphData?.type);         // Content type (e.g., "website", "article")
print(openGraphData?.locale);       // Content locale (e.g., "en_US")

Raw Metadata Access

For advanced use cases, you can also access the raw metadata:

// Fetch raw OpenGraph data
final rawData = await opengraph_fetch_raw("https://datogedon.com");

// Access the raw data
print(rawData?.title);
print(rawData?.description);
// ... other properties

Supported Metadata Formats

The package can extract metadata from multiple formats:

  1. OpenGraph Protocol: Standard og: meta tags (Facebook, most social platforms)
  2. Twitter Cards: Twitter-specific metadata format
  3. HTML Meta Tags: Standard HTML meta tags for title, description, etc.
  4. JSON-LD: Structured data in JSON-LD format (commonly used for SEO)

The extraction process follows a priority order, with OpenGraph tags taking precedence when available, followed by Twitter Cards, then JSON-LD, and finally standard HTML meta tags.

Complete Example

import 'package:flutter/material.dart';
import 'package:opengraph/opengraph.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: const Text('OpenGraph Preview'),
        ),
        body: Column(
          children: [
            // Example of using the OpengraphPreview widget
            const Padding(
              padding: EdgeInsets.all(8.0),
              child: OpengraphPreview(
                url: "https://www.youtube.com/watch?v=6g4dkBF5anU",
              ),
            ),
            
            // Example of using the opengraph_fetch functionality
            FutureBuilder(
              future: opengraph_fetch("https://github.com/baldomerocho/flutter_opengraph"),
              builder: (context, snapshot) {
                if (snapshot.connectionState == ConnectionState.waiting) {
                  return const CircularProgressIndicator();
                }
                if (snapshot.hasError || !snapshot.hasData) {
                  return const Text("Error fetching data");
                }
                final data = snapshot.data!;
                return Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: Card(
                    child: Padding(
                      padding: const EdgeInsets.all(8.0),
                      child: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Text("Title: ${data.title}", style: Theme.of(context).textTheme.titleMedium),
                          Text("Description: ${data.description}"),
                          if (data.image.isNotEmpty)
                            Image.network(data.image, height: 100),
                        ],
                      ),
                    ),
                  ),
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

## Advanced Usage

### Combining Both Features

You can use both the widget and fetch functionality together in your app. For example, you might want to display a preview widget but also use the metadata for other purposes:

```dart
FutureBuilder(
  future: opengraph_fetch("https://flutter.dev"),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const CircularProgressIndicator();
    }
    
    // Display the preview widget
    return Column(
      children: [
        // Use the widget for visual preview
        const OpengraphPreview(url: "https://flutter.dev"),
        
        // Also use the fetched data for other purposes
        if (snapshot.hasData)
          Text("This content is from: ${snapshot.data!.siteName}"),
      ],
    );
  },
)

Error Handling

The package includes built-in error handling to ensure your app remains stable even when URLs are invalid or content cannot be fetched:

try {
  final data = await opengraph_fetch("https://invalid-url.example");
  // Handle success case
} catch (e) {
  // Handle error case
  print("Error fetching OpenGraph data: $e");
}

Best Practices

Performance Optimization

  1. Configure Cache Size: Set an appropriate OpengraphCache.maxEntries value based on your app's memory constraints
  2. Long Lists: In scrollable lists with many previews set enableBlur: falseBackdropFilter is expensive per item
  3. Prefetching: Consider prefetching OpenGraph data (opengraph_fetch(url)) for important links — results land in the cache and the widget picks them up instantly

Legacy API

OpenGraphRequest / OpenGraphConfiguration (the pre-1.0 singleton API) are deprecated as of 1.3.0 and will be removed in 2.0.0. They keep working — and now send the configured request headers and decode non-UTF-8 charsets — but only parse og: tags. New code should use opengraph_fetch and OpengraphCache, which also parse Twitter Card, JSON-LD and HTML meta fallbacks.

UI Integration

  1. Fallback UI: Always provide fallback UI for cases where OpenGraph data might be missing
  2. Loading States: Show appropriate loading indicators while data is being fetched
  3. Error States: Handle error states gracefully with user-friendly messages

Contribution

Contributions are welcome! If you find any issues or have suggestions for improvements, please feel free to open an issue or submit a pull request on the GitHub repository.

License

This package is available under the MIT License.

Libraries

opengraph
@project : opengraph @author : Baldomero (datogedon@gmail.com) @link : https://github.com/baldomerocho/flutter_opengraph/ @Disc : a dart and flutter package to fetch and preview OpenGraph data
opengraph_fetch
This library provides metadata parsers and utility functions for retrieving and parsing documents from a URL.