<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet href="/vendor/feed/atom.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en-US">
                        <id>https://3.screeenly.com/rss</id>
                                <link href="https://3.screeenly.com/rss" rel="self"></link>
                                <title><![CDATA[screeenly]]></title>
                    
                                <subtitle>Learn more about how screeenly is built, what is going on behind the scenes, what new features we&#039;re working on or improvements we&#039;re making.</subtitle>
                                                    <updated>2026-11-06T09:05:00+00:00</updated>
                        <entry>
            <title><![CDATA[Let your agent take screenshots]]></title>
            <link rel="alternate" href="https://3.screeenly.com/blog/mcp-server" />
            <id>https://3.screeenly.com/blog/mcp-server</id>
            <author>
                <name><![CDATA[Stefan Zweifel]]></name>
            </author>
            <summary type="html">
                <![CDATA[<p>Coding agents are good at changing a page and bad at looking at it. They can't open a browser unless you give them one, and running Chrome next to an agent is more setup than most people want.</p>
<p>screeenly now runs an MCP server. Add it to your agent once, and it can take a screenshot of a page, turn a page or some HTML into a PDF, or read the HTML of a JavaScript app after it rendered.</p>
<h2>Set it up</h2>
<p>The server is at <code>https://3.screeenly.com/mcp</code> and uses the same API tokens as the REST API. Create a token in your <a href="https://3.screeenly.com/app">dashboard</a>, then add the server to your client.</p>
<p>Claude Code:</p>
<pre><code class="language-bash">claude mcp add --transport http screeenly https://3.screeenly.com/mcp \
  --header &quot;Authorization: Bearer YOUR_API_TOKEN&quot;
</code></pre>
<p>Cursor, in <code>.cursor/mcp.json</code>:</p>
<pre><code class="language-json">{
  &quot;mcpServers&quot;: {
    &quot;screeenly&quot;: {
      &quot;url&quot;: &quot;https://3.screeenly.com/mcp&quot;,
      &quot;headers&quot;: {
        &quot;Authorization&quot;: &quot;Bearer YOUR_API_TOKEN&quot;
      }
    }
  }
}
</code></pre>
<p>Other clients work the same way: add a remote HTTP server with that URL and an <code>Authorization</code> header. The <a href="https://3.screeenly.com/app/mcp">MCP page in your dashboard</a> has these snippets with copy buttons.</p>
<h2>The tools</h2>
<table>
<thead>
<tr>
<th>Tool</th>
<th>What it does</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>capture_screenshot</code></td>
<td>Takes a screenshot (JPG, PNG, WebP) or creates a PDF of a URL or of HTML. Accepts most options of the screenshot API, such as <code>window_width</code>, <code>full_page</code> and <code>selector</code>.</td>
</tr>
<tr>
<td><code>get_rendered_html</code></td>
<td>Loads a URL or HTML in Chrome, runs its JavaScript and returns the resulting HTML.</td>
</tr>
<tr>
<td><code>get_usage</code></td>
<td>Returns the plan, the requests used this month, the monthly limit and the credit balance.</td>
</tr>
<tr>
<td><code>list_recent_shots</code></td>
<td>Lists the most recent captures of the account, newest first.</td>
</tr>
</tbody>
</table>
<p>Then ask in plain words, for example: &quot;Take a screenshot of our pricing page at 390 pixels wide and attach it to the pull request.&quot;</p>
<h2>Usage and limits</h2>
<p>Captures through MCP count toward your monthly usage like API requests, and cached results are free. When you reach your limit, the tools return an error that explains why, so the agent tells you instead of retrying.</p>
<p>Download URLs are valid for 24 hours.</p>
<h2>Give each agent its own token</h2>
<p>Create a separate token for each agent or tool. The request log shows which captures came from MCP, and you can revoke one token without breaking the others.</p>
<p>If an agent only needs to check the usage or list earlier captures, create a token with only the <code>shot:read</code> ability. It can't create new captures.</p>
<h2>Not sure what to ask?</h2>
<p>Open the <a href="https://3.screeenly.com/app/playground">playground</a>, set the options you want and copy the request as an agent prompt. It lists every option you set, so the agent sends the same request.</p>
<p>The MCP server is part of every plan, including the free plan. Questions? Email <a href="mailto:support@screeenly.com">support@screeenly.com</a>.</p>
]]>
            </summary>
                                    <updated>2026-11-06T09:05:00+00:00</updated>
        </entry>
            <entry>
            <title><![CDATA[Identical requests are now free]]></title>
            <link rel="alternate" href="https://3.screeenly.com/blog/caching" />
            <id>https://3.screeenly.com/blog/caching</id>
            <author>
                <name><![CDATA[Stefan Zweifel]]></name>
            </author>
            <summary type="html">
                <![CDATA[<p>Until now, every request to screeenly started a browser, even if you had asked for the same screenshot a minute earlier. Each of those requests counted toward your monthly usage.</p>
<p>Starting today, screeenly remembers the result. When you send a request that matches an earlier successful request of your account, you get the stored file back. It's faster, and it doesn't count toward your usage or use a credit.</p>
<h2>What counts as the same request</h2>
<p>Two requests match when they go to the same endpoint with the same URL (or the same HTML) and the same options. Options you leave out and options set to their default value are treated the same. Cookies, HTTP headers and basic auth credentials are part of the match, so a request with a different session cookie renders again.</p>
<p>The scheme and the host of the URL are compared without case, and the <code>#fragment</code> is ignored. The path and the query string have to match exactly.</p>
<p>Results are only reused within your own account. Another account never gets your files.</p>
<h2>Files are kept for 24 hours</h2>
<p>Screenshots, PDFs and rendered HTML used to expire after 60 minutes. They are now kept for 24 hours, and a matching request returns the stored result during that time. The <code>expires_at</code> field in the response tells you when the file goes away.</p>
<p>Playground results still expire after 60 minutes and are never reused.</p>
<h2>How to tell a cached result from a new one</h2>
<table>
<thead>
<tr>
<th></th>
<th>New render</th>
<th>From the cache</th>
</tr>
</thead>
<tbody>
<tr>
<td>Status code</td>
<td><code>201</code></td>
<td><code>200</code></td>
</tr>
<tr>
<td><code>X-Cache</code> header</td>
<td><code>MISS</code></td>
<td><code>HIT</code></td>
</tr>
<tr>
<td>Counts toward usage</td>
<td>Yes</td>
<td>No</td>
</tr>
</tbody>
</table>
<p>If your code checks for <code>201</code> exactly, change it to accept any <code>2xx</code> status.</p>
<h2>Render again, or keep files for less time</h2>
<p>On a paid plan or with credits, you control the cache per request:</p>
<ul>
<li><code>cache=false</code> skips the lookup and always renders a new file. Use it if you capture the same page to see whether it changed.</li>
<li><code>cache_ttl</code> sets how long the result is kept and reused, from 60 to 86,400 seconds. Use a short value if you don't want the file stored for a full day.</li>
</ul>
<pre><code class="language-bash">curl --request POST \
  --url https://3.screeenly.com/api/v1/shots \
  --header &quot;Authorization: Bearer $TOKEN&quot; \
  --data url=https://example.com \
  --data cache=false
</code></pre>
<p>Accounts on the free plan always use the cache with the 24 hour default.</p>
<h2>Retry a request without paying twice</h2>
<p>There's a second way to avoid paying for the same work twice. Send an <code>X-Request-ID</code> header with a value of your choice. If the connection drops and you send the same request with the same ID again, screeenly returns the first response and adds <code>X-Request-Replayed: true</code>. The retry isn't charged.</p>
<ul>
<li>If you use the ID for a different request, you get a <code>422</code>.</li>
<li>If the first request is still running, you get a <code>409</code>. Wait for it and retry.</li>
<li>Failed requests aren't stored, so you can retry them with the same ID.</li>
</ul>
<p>If you don't send the header, screeenly creates an ID for you and returns it in the <code>X-Request-ID</code> response header. Include it when you email support about a request.</p>
<p>Questions? Email <a href="mailto:support@screeenly.com">support@screeenly.com</a>.</p>
]]>
            </summary>
                                    <updated>2026-11-06T09:05:00+00:00</updated>
        </entry>
            <entry>
            <title><![CDATA[screeenly now has a free plan]]></title>
            <link rel="alternate" href="https://3.screeenly.com/blog/free-plan" />
            <id>https://3.screeenly.com/blog/free-plan</id>
            <author>
                <name><![CDATA[Stefan Zweifel]]></name>
            </author>
            <summary type="html">
                <![CDATA[<p>Every screeenly account now gets <strong>100 free requests every month</strong>. You don't need a credit card or a subscription, and the requests renew at the start of every month. The free plan replaces the 14-day trial.</p>
<h2>What changes for you</h2>
<p><strong>If your trial ran out</strong>, your API tokens work again. You can make 100 requests a month without doing anything.</p>
<p><strong>If you're on a plan</strong>, the 100 free requests are added on top of your plan. Small now includes 2,100 requests a month, Base 10,100, and so on.</p>
<p><strong>If you're new</strong>, you can sign up and start using the API right away. There's no trial that ends after 14 days.</p>
<h2>Limits on the free plan</h2>
<p>Accounts without a plan and without credits have lower limits:</p>
<ul>
<li>Window and clip size up to 1920 × 1080 pixels, with a <code>device_scale_factor</code> of 1</li>
<li><code>delay</code> up to 2,000 ms and <code>timeout</code> up to 15 seconds</li>
<li>No full page screenshots</li>
<li>One request at a time, and 10 requests per minute</li>
<li>Results are always cached for 24 hours. Identical requests return the stored result and don't count toward your usage.</li>
</ul>
<p>A request above one of these limits fails with a message that says which limit it hit. As soon as you have a plan or any credits, the limits are the same as on every paid plan.</p>
<h2>Credits for the months you need more</h2>
<p>You can now buy credits next to your plan, or without one:</p>
<table>
<thead>
<tr>
<th>Credits</th>
<th>Price</th>
<th>Per request</th>
</tr>
</thead>
<tbody>
<tr>
<td>1,000</td>
<td>$9</td>
<td>$0.009</td>
</tr>
<tr>
<td>2,000</td>
<td>$16</td>
<td>$0.008</td>
</tr>
<tr>
<td>5,000</td>
<td>$35</td>
<td>$0.007</td>
</tr>
<tr>
<td>10,000</td>
<td>$60</td>
<td>$0.006</td>
</tr>
<tr>
<td>20,000</td>
<td>$100</td>
<td>$0.005</td>
</tr>
<tr>
<td>50,000</td>
<td>$200</td>
<td>$0.004</td>
</tr>
</tbody>
</table>
<p>One credit pays for one request, whether it's a screenshot, a PDF or rendered HTML. Credits are only used once your monthly requests run out, and they don't expire. Prices are in USD and exclude tax. If you need more than 50,000 credits at once, <a href="mailto:support@screeenly.com">email us</a>.</p>
<p>You buy credits on the <a href="https://3.screeenly.com/app/billing/credits">billing page</a>. Every change to your balance shows up there: purchases, credits we add for you, and each request that was paid with a credit.</p>
<p>If you use the API every month, a plan is still the cheaper option. Small costs $15 for 2,100 requests a month.</p>
<h2>Requests that fail validation are free</h2>
<p>A request that fails validation (for example, a missing <code>url</code> or an invalid <code>window_width</code>) no longer counts toward your monthly usage and doesn't use a credit. Requests that fail while rendering or time out still count, because the browser already ran.</p>
<h2>New response headers</h2>
<p>Every API response now includes two headers, so you can watch your usage from your code:</p>
<ul>
<li><code>X-Usage-Remaining</code>: requests left this month</li>
<li><code>X-Credits-Remaining</code>: your credit balance</li>
</ul>
<p>When your monthly requests and your credits are both used up, the API returns <code>403</code> until the next month starts, the same as before.</p>
<p>Questions? Email <a href="mailto:support@screeenly.com">support@screeenly.com</a>.</p>
]]>
            </summary>
                                    <updated>2026-11-06T09:05:00+00:00</updated>
        </entry>
            <entry>
            <title><![CDATA[A new look for screeenly]]></title>
            <link rel="alternate" href="https://3.screeenly.com/blog/redesign" />
            <id>https://3.screeenly.com/blog/redesign</id>
            <author>
                <name><![CDATA[Stefan Zweifel]]></name>
            </author>
            <summary type="html">
                <![CDATA[<p>screeenly has a new design. The website, the dashboard and every email we send look different starting today. This post lists what changed and links to the posts with the details.</p>
<h2>The website</h2>
<p>Every feature now has its own page: <a href="https://3.screeenly.com/features/screenshots">screenshots</a>, <a href="https://3.screeenly.com/features/pdf">PDFs</a>, <a href="https://3.screeenly.com/features/your-own-html">your own HTML</a>, <a href="https://3.screeenly.com/features/rendered-html">rendered HTML</a> and the <a href="https://3.screeenly.com/features/mcp">MCP server</a>. Each page lists the options, code you can copy and the questions we get most often.</p>
<p>We also added <a href="https://3.screeenly.com/compare">comparisons</a> with other screenshot APIs. They include the cases where another service fits better.</p>
<h2>The dashboard</h2>
<p>The dashboard was rebuilt from scratch. It shows your free requests, your plan allowance and your credit balance in one place, and the request log shows whether a request came from the API, the MCP server or the playground.</p>
<p>Some pages moved:</p>
<ul>
<li>Billing, credits and receipts: <code>/app/billing</code></li>
<li>Account settings: <code>/app/account</code></li>
<li>Request log: <code>/app/request-log</code></li>
</ul>
<p>New accounts get a checklist that walks them from the first API token to the first request. The playground can copy any request as curl, as PHP, or as a prompt you can paste into your agent.</p>
<h2>A free plan instead of the trial</h2>
<p>Every account gets 100 free requests a month, and you can buy credits for the months you need more. We wrote about it in <a href="https://3.screeenly.com/blog/free-plan">screeenly now has a free plan</a>.</p>
<h2>Changes to the API</h2>
<p>Two changes can affect code that already uses the API:</p>
<ul>
<li><strong>Identical requests return the stored result for free.</strong> The response is <code>200</code> with <code>X-Cache: HIT</code> instead of a new render with <code>201</code>. Send <code>cache=false</code> to render again.</li>
<li><strong>Files are kept for 24 hours instead of 60 minutes.</strong></li>
</ul>
<p>The details, and the other API changes, are in <a href="https://3.screeenly.com/blog/caching">Identical requests are now free</a> and <a href="https://3.screeenly.com/blog/api-changes-november-2026">API changes in November 2026</a>.</p>
<h2>Screenshots for your agent</h2>
<p>screeenly now runs an MCP server, so Claude, Cursor and other MCP clients can take screenshots and create PDFs with your API token. See <a href="https://3.screeenly.com/blog/mcp-server">Let your agent take screenshots</a>.</p>
<h2>Our numbers</h2>
<p>screeenly started as an open source project in July 2014 and has handled more than 21 million requests since. The <a href="https://3.screeenly.com/open">open startup page</a> shows revenue, users and requests per month.</p>
<p>If something looks broken or works differently than before, email <a href="mailto:support@screeenly.com">support@screeenly.com</a>.</p>
]]>
            </summary>
                                    <updated>2026-11-06T09:00:00+00:00</updated>
        </entry>
            <entry>
            <title><![CDATA[API changes in November 2026]]></title>
            <link rel="alternate" href="https://3.screeenly.com/blog/api-changes-november-2026" />
            <id>https://3.screeenly.com/blog/api-changes-november-2026</id>
            <author>
                <name><![CDATA[Stefan Zweifel]]></name>
            </author>
            <summary type="html">
                <![CDATA[<p>This post lists every change to the API that shipped with the <a href="https://3.screeenly.com/blog/redesign">redesign</a>. Caching and the longer file retention have <a href="https://3.screeenly.com/blog/caching">their own post</a>.</p>
<h2>Block ads and trackers while a page loads</h2>
<p>Two new options stop the browser from loading resources you don't need:</p>
<ul>
<li><code>block_urls</code>: skip every request whose URL contains one of these strings.</li>
<li><code>block_domains</code>: skip every request to these domains.</li>
</ul>
<pre><code class="language-bash">curl --request POST \
  --url https://3.screeenly.com/api/v1/shots \
  --header &quot;Authorization: Bearer $TOKEN&quot; \
  --data url=https://example.com \
  --data &quot;block_domains[]=googletagmanager.com&quot; \
  --data &quot;block_urls[]=/ads/&quot;
</code></pre>
<p>Both accept up to 50 entries. They work for screenshots, PDFs and rendered HTML, and in the playground.</p>
<h2>New maximums</h2>
<p>Some options could be set to values that Chrome can't render, or that made a request run for minutes. They now have limits. A request above a limit fails validation with a <code>422</code>, which doesn't count toward your usage.</p>
<table>
<thead>
<tr>
<th>Field</th>
<th>Maximum</th>
</tr>
</thead>
<tbody>
<tr>
<td>Screenshot size</td>
<td>16,384 pixels per side and 40 megapixels in total. The window or clip size is multiplied by <code>device_scale_factor</code> first.</td>
</tr>
<tr>
<td><code>clip_width</code>, <code>clip_height</code></td>
<td>Same as the screenshot size. They had no limit before.</td>
</tr>
<tr>
<td><code>paper_width</code>, <code>paper_height</code></td>
<td>5,000 mm (was 100,000 mm)</td>
</tr>
<tr>
<td><code>html</code></td>
<td>2,000,000 characters</td>
</tr>
<tr>
<td><code>header_html</code>, <code>footer_html</code></td>
<td>100,000 characters each</td>
</tr>
<tr>
<td><code>http_headers</code>, <code>cookies</code>, <code>block_urls</code>, <code>block_domains</code></td>
<td>50 entries each</td>
</tr>
<tr>
<td>Header values / cookie values</td>
<td>8 KB / 4 KB</td>
</tr>
</tbody>
</table>
<p>A 1440 × 900 window at <code>device_scale_factor=3</code> is 4320 × 2700 pixels, or 11.7 megapixels, and still works. A 10,000 × 10,000 window at 3× doesn't, and never produced a usable image anyway.</p>
<h2>Request IDs</h2>
<p>Every response now has an <code>X-Request-ID</code> header, also when the request failed. Send your own ID in the same header to retry a request safely: a repeat with the same ID returns the first response and isn't charged again. The <a href="https://3.screeenly.com/blog/caching">caching post</a> explains how it works.</p>
<p>Include the request ID when you email support about a request. We can find it in our logs right away.</p>
<h2>Token abilities</h2>
<p>API tokens now have abilities, and the API checks them:</p>
<ul>
<li><code>shot:create</code> creates screenshots, PDFs and rendered HTML. The API needs it.</li>
<li><code>shot:read</code> lists your captures and reads your usage over the <a href="https://3.screeenly.com/blog/mcp-server">MCP server</a>.</li>
</ul>
<p><code>shot:create</code> includes <code>shot:read</code>. Every existing token has <code>shot:create</code> and keeps working.</p>
<h2>Requests that fail validation are free</h2>
<p>A request that fails validation, for example with a missing <code>url</code> or a <code>window_width</code> that's too large, no longer counts toward your usage. Requests that fail while rendering or time out still count, because the browser already ran.</p>
<h2>New response headers</h2>
<table>
<thead>
<tr>
<th>Header</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>X-Request-ID</code></td>
<td>The ID of the request</td>
</tr>
<tr>
<td><code>X-Cache</code></td>
<td><code>HIT</code> when the result came from the cache, <code>MISS</code> otherwise</td>
</tr>
<tr>
<td><code>X-Request-Replayed</code></td>
<td><code>true</code> when the response is a replay of an earlier request with the same ID</td>
</tr>
<tr>
<td><code>X-Usage-Remaining</code></td>
<td>Requests left this month</td>
</tr>
<tr>
<td><code>X-Credits-Remaining</code></td>
<td>Your credit balance</td>
</tr>
</tbody>
</table>
<h2>Fixes</h2>
<ul>
<li>On the 29th to the 31st of a month, the reset date in <code>X-Usage-Resets</code>, <code>meta.usage_limit.resets</code> and the dashboard was one month too late. It's correct now.</li>
<li>Many requests sent at the same moment could go past the monthly limit. The limit is now checked and counted in one step.</li>
</ul>
<p>The <a href="https://docs.3.screeenly.com/reference/">API reference</a> lists every option with its limits. Questions? Email <a href="mailto:support@screeenly.com">support@screeenly.com</a>.</p>
]]>
            </summary>
                                    <updated>2026-11-06T09:00:00+00:00</updated>
        </entry>
    </feed>
