simple_link_preview 2.1.0 copy "simple_link_preview: ^2.1.0" to clipboard
simple_link_preview: ^2.1.0 copied to clipboard

Lightweight link previews for HTML metadata, direct images, and other web content types.

Simple Link Preview #

Fetch lightweight metadata for HTTP and HTTPS links. HTML responses are parsed only from the document <head>, while images and other content types are returned without downloading their full body.

Installation #

dependencies:
  simple_link_preview: ^2.1.0

Usage #

import 'dart:convert';

import 'package:simple_link_preview/simple_link_preview.dart';

Future<void> main() async {
  final preview = await SimpleLinkPreview.getPreview(
    'https://pub.dev/',
    options: const LinkPreviewOptions(
      timeout: Duration(seconds: 10),
      maxHtmlBytes: 1024 * 1024,
      maxRedirects: 5,
    ),
    onError: (error) async {
      print('Could not load preview: $error');
      return null;
    },
  );
  if (preview == null) {
    print('The preview could not be loaded.');
    return;
  }

  if (!preview.hasMetadata) {
    print('The resource loaded successfully but has no preview metadata.');
    return;
  }

  print(jsonEncode(preview.toJson()));
}

Example HTML result:

{
  "url": "https://pub.dev/",
  "contentType": "text/html",
  "title": "Dart packages",
  "image": "https://pub.dev/static/img/pub-dev-icon-cover-image.png",
  "icon": "https://pub.dev/favicon.ico",
  "description": "The official package repository for Dart and Flutter apps."
}

Result fields #

Field Description
url Original URL supplied by the caller.
contentType Normalized MIME type without parameters such as charset.
title Page title extracted from HTML metadata.
description Page description extracted from HTML metadata.
image Metadata image, or the requested resource URL for image/*.
icon Page icon declared in the HTML <head>.
hasMetadata Whether at least one non-blank title, description, image, or icon is available.

The result has three distinct states:

  • null: the preview could not be loaded.
  • A LinkPreview with hasMetadata == false: the resource loaded successfully, but it has no metadata useful for rendering a preview.
  • A LinkPreview with hasMetadata == true: at least one display metadata field is available.

All stored fields except url are nullable. hasMetadata is a derived getter; url, contentType, and blank metadata values do not make it true. Use toJson() to convert the stored preview fields into a JSON-compatible map.

onError is optional and defaults to null. When provided, it receives a structured LinkPreviewException and may asynchronously return a fallback LinkPreview. Without a handler, failures result in null.

final preview = await SimpleLinkPreview.getPreview(
  url,
  onError: (error) async {
    print(error.code);
    print(error.statusCode);
    print(error.message);
    return null;
  },
);

Verified failures use these stable error codes:

Error code Meaning
invalidUrl URL is not an absolute HTTP or HTTPS URL.
invalidOptions A configurable limit is invalid.
httpStatus validateStatus rejected the response; statusCode is available.
timeout Sending or reading exceeded the configured timeout.
network HTTP client could not complete the request.
parsing Response metadata could not be parsed or resolved.
unexpected An otherwise unclassified failure occurred.

LinkPreviewOptions exposes timeout, maxHtmlBytes, maxRedirects, and a validateStatus callback modeled after Dio. By default, only statuses from 200 through 299 are accepted. A response rejected by this callback is reported as httpStatus.

To parse metadata from selected error pages while preserving the default successful range:

final preview = await SimpleLinkPreview.getPreview(
  url,
  options: LinkPreviewOptions(
    validateStatus: (statusCode) =>
        statusCode >= 200 && statusCode < 300 || statusCode == 404,
  ),
);

Content-type behavior #

  • image/*: returns the final URL after redirects in image.
  • text/html and application/xhtml+xml: parses metadata from <head>.
  • Missing Content-Type: sniffs at most the first 1 KB for common HTML roots, then parses the bounded HTML head only when HTML is detected.
  • Other successful types, such as PDF, video, audio, or JSON: returns the normalized contentType and leaves unavailable metadata fields as null.
  • Invalid URLs, invalid options, timeouts, network failures, redirect failures, and statuses rejected by validateStatus are reported through onError. They return null when no handler or fallback preview is provided.

HTML metadata uses the following priority. Open Graph values use the standard property attribute first and accept name as a compatibility fallback:

  • Title: Open Graph, Twitter Card, then <title>.
  • Description: Open Graph, Twitter Card, then standard description metadata.
  • Image: Open Graph, Twitter Card, then itemprop="image".
  • Icon: Apple touch icon, standard link icon, then Microsoft tile image.

Empty or invalid HTTP(S) image and icon candidates are skipped. Relative metadata URLs honor the first valid HTTP(S) <base href> and otherwise resolve against the final response URL.

The package does not inspect <img> elements in the document body and does not make a separate favicon request.

Network limits #

  • Uses one logical streamed GET request; the HTTP client may follow redirects.
  • Reads HTML until </head> or a maximum of 1 MB. The 1 MB value is only an upper bound; reading stops earlier as soon as the closing head tag is found.
  • Uses one 10-second end-to-end deadline by default and follows at most five redirects.
  • Accepts only absolute HTTP and HTTPS URLs.

On web platforms, cross-origin requests remain subject to the target server's CORS policy.

Features and bugs #

Please file feature requests and bugs at the issue tracker.

14
likes
160
points
296
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

Lightweight link previews for HTML metadata, direct images, and other web content types.

Repository (GitHub)
View/report issues

License

AGPL-3.0 (license)

Dependencies

html, http

More

Packages that depend on simple_link_preview