SnapRender
  1. Home
  2. Blog
  3. Website Screenshots in WordPress with wp_remote_get (Plugin Snippet)

Website Screenshots in WordPress with wp_remote_get (Plugin Snippet)

A small WordPress plugin that captures a screenshot of any URL through a screenshot API: a shortcode, transient caching, saving the image to the media library, and setting it as a featured image.

Link directories, curated lists, "sites we like" pages: WordPress sites keep needing a thumbnail of some other website. Most plugins for this either stopped working years ago or run a fragile headless browser on shared hosting. The version below is a few dozen lines, uses only WordPress core functions, and lets an API do the rendering.

Try it on your URL

Live capture, no signup. You get the screenshot and the exact API call that produced it.

The plugin

Create wp-content/plugins/site-screenshots/site-screenshots.php:

<?php
/**
 * Plugin Name: Site Screenshots
 * Description: [site_screenshot url="https://example.com"] renders a live thumbnail of any website.
 */

if (! defined('ABSPATH')) {
    exit;
}

function ssr_capture_url(string $url, string $format = 'jpeg'): ?string
{
    if (! defined('SNAPRENDER_API_KEY')) {
        return null;
    }

    $key = 'ssr_' . md5($url . $format);
    $cached = get_transient($key);
    if ($cached) {
        return $cached;
    }

    $endpoint = add_query_arg([
        'url' => rawurlencode($url),
        'format' => $format,
        'block_cookie_banners' => 'true',
        'cache_ttl' => 86400,
    ], 'https://app.snap-render.com/v1/screenshot');

    $response = wp_remote_get($endpoint, [
        'headers' => ['X-API-Key' => SNAPRENDER_API_KEY],
        'timeout' => 60,
    ]);

    if (is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
        return null;
    }

    $body = wp_remote_retrieve_body($response);
    $upload = wp_upload_bits(md5($url) . '.' . $format, null, $body);
    if (! empty($upload['error'])) {
        return null;
    }

    set_transient($key, $upload['url'], DAY_IN_SECONDS);
    return $upload['url'];
}

add_shortcode('site_screenshot', function ($atts) {
    $atts = shortcode_atts(['url' => '', 'width' => '640'], $atts);
    if (! $atts['url']) {
        return '';
    }
    $src = ssr_capture_url(esc_url_raw($atts['url']));
    if (! $src) {
        return '';
    }
    return sprintf(
        '<img src="%s" alt="%s" width="%d" loading="lazy">',
        esc_url($src),
        esc_attr(wp_parse_url($atts['url'], PHP_URL_HOST)),
        (int) $atts['width']
    );
});

Add the key to wp-config.php:

define('SNAPRENDER_API_KEY', 'sk_live_your_key');

Activate the plugin and [site_screenshot url="https://example.com"] in any post renders the thumbnail. The first view captures and saves the file to the uploads folder; every view for the next day reads the transient and never calls out.

Or skip the setup entirely

Everything in this guide is one GET request with SnapRender. No browser to babysit, no timeouts to tune.

200 screenshots a month free. First render in under a minute.

Grab a free API key

Featured image from a URL

For a directory where each post is a site, set the screenshot as the featured image when the post is saved:

add_action('save_post', function ($post_id, $post) {
    if ($post->post_type !== 'site' || has_post_thumbnail($post_id)) {
        return;
    }
    $url = get_post_meta($post_id, 'site_url', true);
    if (! $url) {
        return;
    }

    require_once ABSPATH . 'wp-admin/includes/media.php';
    require_once ABSPATH . 'wp-admin/includes/file.php';
    require_once ABSPATH . 'wp-admin/includes/image.php';

    $src = ssr_capture_url($url);
    if (! $src) {
        return;
    }
    $attachment_id = media_sideload_image($src, $post_id, null, 'id');
    if (! is_wp_error($attachment_id)) {
        set_post_thumbnail($post_id, $attachment_id);
    }
}, 10, 2);

This assumes a custom post type site with a site_url meta field; adjust the names to your setup. Because the save hook runs on the admin request, a slow target page delays the editor's save by the capture time. If that bothers editors, move the call into a WP-Cron event.

Notes on limits and costs

  • The free plan is 200 renders a month; with the transient cache and cache_ttl on the API, a directory of 200 sites costs about 200 renders on day one and near zero afterwards.
  • wp_remote_get returns a WP_Error on network failure and a non-200 code on capture failure; both paths return null above, so the page renders without an image instead of breaking.
  • For a full-page capture add 'full_page' => 'true' to the query; for a mobile look add 'device' => 'iphone_15_pro'.

No key at all

For a preview image with no account, the keyless embed is one tag: <img src="https://app.snap-render.com/v1/embed?url=https://example.com" width="640">. It shares a daily budget and serves a neutral placeholder when the budget is gone, so use it for low-volume pages and the plugin above when you want guaranteed renders.

Related: PHP quickstart, website thumbnails, link previews.

Frequently asked questions

Does this need anything installed on the hosting server?

No. It uses wp_remote_get, which every WordPress install has. The browser that renders the page runs behind the API.

Where should the API key be stored?

As a constant in wp-config.php (SNAPRENDER_API_KEY). Keep it out of theme files and out of the database options table if you can.

Will it slow down page loads?

Not after the first render: the snippet caches the image URL in a transient for a day, and the API caches the render on its side, so repeat views cost nothing.

Can I save the screenshot as a featured image?

Yes. The second function downloads the image into the media library with media_sideload_image and sets it as the post thumbnail.

Or skip the setup entirely

200 screenshots a month free. First render in under a minute.