How I crafted TL;DRs with LLMs and modernized my blog (part 4)

tl;dr: I optimized all my blog images for performance, making Lighthouse happy. I fixed slow zooming by tweaking the Cache-Control HTTP header on Netlify. Improving alt text with GPT-4.1 made me wonder how I ever managed without an LLM in my toolkit!
View the series
  1. See how I crafted story-like tl;drs for my posts with LLMs
  2. Learn how I generated my llms.txt summary with LLMs
  3. Grab the "Copy page" button's code, as seen in OpenAI docs
  4. Check how I optimized images for better blog performance
  5. See how impressed I was by GPT-4.1's meta descriptions

To improve performance, I used Lighthouse ↗. Lighthouse mostly complained about images, so most of my work went into optimizing them.

This was expected. I hadn't done much about images before, other than converting original png files to webp.

Using responsive images

I started by adding responsive images and lazy loading those that are off-screen:

<img
  src="/img/original/2025-08-12-sheets2gmail-spreadsheet.webp"
  srcset="
          /img/420/2025-08-12-sheets2gmail-spreadsheet.webp   420w,
          /img/640/2025-08-12-sheets2gmail-spreadsheet.webp   640w,
          /img/840/2025-08-12-sheets2gmail-spreadsheet.webp   840w,
          /img/1280/2025-08-12-sheets2gmail-spreadsheet.webp 1280w
          "
  sizes="(max-width: 640px) 100vw, 640px"
  width="1202"
  height="988"
  loading="lazy"
  alt="Automating Gmail sends with Google Sheets updates"
/>

Why these specific widths?

Because, except for my profile picture, images are always inside an element capped at 640px max-width. And considering today's mobile screens max out at about 410px wide and device pixel ratios (DPR) can be 2 or 3, these sizes make sense:

  • 420,

  • 640,

  • 840 (420 × 2DPR) and

  • 1280 (420 × 3DPR).

To resize the images, I used the convert utility from ImageMagick ↗ with this script:

#!/usr/bin/env bash

for size in 420 640 840 1280; do
  echo "Resizing => $size"
  mkdir -p ./assets/img/$size
  fd -e webp . ./assets/img/original | while read -r src; do
    filename=$(basename "$src")
    target="./assets/img/$size/$filename"
    if [ ! -f "$target" ]; then
      convert "$src" -resize ${size}x "$target"
      echo "  $filename"
    fi
  done
done

The original images are in the ./assets/img/original/ directory. They're resized into the 420, 640, 840, and 1280 subdirectories under ./assets/img/.

For images that are in the viewport when the page first loads (like in this post), I explicitly set the loading attribute to eager.

Get my thoughts on working with AI

No spam. Unsubscribe anytime.

Prefetching full-size images for zoom

All images can be zoomed by clicking on them. When you do, the original image (set in src on <img>) is used.

Zoomed-in view of the Detailed OpenAI Traces user interface, highlighting AI agent workflow steps and span analytics for real-world automation processes, as shown in a modal window.  Screenshot from tonyaldon.com, exploring practical LLM automation, troubleshooting, and workflow optimization.

Now that I use responsive images, the full-size version isn't always loaded by default. This caused some lag when clicking to zoom.

To fix that, I added this snippet to prefetch full-size images after DOMContentLoaded, so zooming in is instant:

document.addEventListener("DOMContentLoaded", function () {
  document.querySelectorAll("img").forEach(function (img) {
    const preImg = new Image();
    preImg.src = img.src;
  });
});

Funny enough, prefetching wasn't enough, there was still some lag. Checking the Network tab in DevTools showed the src image was fetched twice: once for prefetch, and again when zooming.

Why?

Because the Cache-Control HTTP header from my dev server (browsersync ↗) was set to public, max-age=0. This tells the browser to check page with the server on every use, leading to a 304 Not Modified and a delay.

Screenshot of Chrome DevTools Network tab displaying a refetched image from tonyaldon.com, highlighting the HTTP Cache-Control header and 304 Not Modified status code. Demonstrates efficient image caching and HTTP header configuration for AI automation blog.

Changing Cache-Control for these images to public, max-age=31536000 fixed the refetching problem.

Since I use Netlify ↗, I just added this _headers file at my project's root:

/img/original/*
  Cache-Control: public, max-age=31536000
/img/420/*
  Cache-Control: public, max-age=31536000
/img/640/*
  Cache-Control: public, max-age=31536000
/img/840/*
  Cache-Control: public, max-age=31536000
/img/1280/*
  Cache-Control: public, max-age=31536000

I haven't found a way to configure browser-sync the same way locally.

Preloading the profile picture

My profile picture appears in the viewport as soon as the page loads (on desktop). I considered inlining it as base64 data right in the HTML, but ended up adding a <link> tag in the head to tell the browser to fetch it early, at the right size. This makes me happy enough, even if I still wish it appeared instantly with the text.

<link
  rel="preload"
  as="image"
  imagesrcset="/img/tony-aldon-profile-picture-90x90.webp 90w,
               /img/tony-aldon-profile-picture-180x180.webp 180w,
               /img/tony-aldon-profile-picture-270x270.webp 270w"
  imagesizes="90px"
/>

Improving image descriptions with GPT-4.1

Finally, I improved my hand-written image descriptions (alt attributes) by giving them to GPT-4.1 using this prompt:

I'm writing alt text for images in my blog about AI automation, which
can be described as follows:

This blog is my ongoing, hands-on exploration of AI automation—how to
build, troubleshoot, and refine real-world workflows using LLMs,
automation platforms like Zapier, and both code-based and no-code
tools. Everything here comes from my lived experience learning as I
go, with lots of focus on what's practical, what breaks, and what you
can actually reuse.

I'm Tony Aldon and my blog is served at tonyaldon.com.

I want to optimize the alt attributes for SEO.  Can you improve the
following 29 descriptions, and provide a summary explaining why your
improvements are beneficial for SEO?

Here are the descriptions I finally kept. Most are identical to what GPT-4.1 suggested. I've listed each original and improved version next to each other for comparison:

[original] Google sheets example automation - Send Gmail when Google Sheets updates
[improved] Automating Gmail sends with Google Sheets updates

[original] Google Cloud console - Creating new project sheets2gmail
[improved] Google Cloud Console: creating a new project for Google Sheets to Gmail automation

[original] Google Cloud console - Enabling Google Sheets API
[improved] Enabling Google Sheets API in Google Cloud for automation project

[original] Google Cloud console - Enabling Gmail API
[improved] Activating Gmail API in Google Cloud to enable automated email sending

[original] Google Cloud console - Google Auth platform - Setting up project sheets2gmail
[improved] Setting up authentication for AI automation project sheets2gmail on Google Cloud

[original] Adding test users to Google Auth for sheets2gmail automation project
[improved] Google Cloud console - Google Auth platform - Put aldon.tony@gmail.com test users in project sheets2gmail

[original] Google Cloud console - Google Auth platform - Create OAuth client ID in project sheets2gmail
[improved] Creating Google OAuth client ID for secure workflow automation in sheets2gmail

[original] Google Cloud console - credentials information in project sheets2gmail
[improved] Viewing API credentials for Google Sheets to Gmail automation project

[original] Sign in with Google
[improved] Sign-in prompt using Google account for automation project

[original] Sign in with Google - sheets2gmail wants access to your google account
[improved] Google sign-in permissions request from sheets2gmail automation app

[original] Google sheets example for Zapier automation - Send Gmail when Google Sheets updates
[improved] Google Sheets and Zapier integration: automate Gmail email sending on sheet updates

[original] Zapier Zap editor - Automation - Send Gmail when Google Sheets updates
[improved] Zapier Zap editor: building Gmail automation triggered by Google Sheets changes

[original] Zapier Zap history dasboard
[improved] Zapier Zap history dashboard showing execution logs for automated workflows

[original] Troubleshooting a Zapier Zap run in the Zap editor - Automation - Send Gmail when Google Sheets updates
[improved] Troubleshooting a Google Sheets to Gmail automation run in Zapier Zap editor

[original] Troubleshoot tab with AI generated information in Zapier Zap editor
[improved] AI-generated troubleshooting suggestions in Zapier automation editor

[original] Troubleshoot tab with AI generated information in Zapier Zap editor
[improved] AI-powered diagnostic tab showing error info in Zapier automation editor

[original] Zapier Zap editor showing no information in Logs tab given the error is due to missing required information
[improved] Zapier editor Logs tab empty due to missing required automation input data

[original] Zapier notice indicating they stopped integrating with Twitter API
[improved] Zapier platform notice: end of Twitter API integration for automations


[original] OpenAI best practices to define function tools in the context of AI agents
[improved] OpenAI documentation: best practices for defining function tools in AI agent workflows

[original] AI agents, Responses API, function tools and handoffs visualized in OpenAI Traces UI
[improved] Visualization of AI agents, API responses, and function tool handoffs in OpenAI Traces UI

[original] AI agents and OpenAI Traces dasboard
[improved] OpenAI Traces dashboard monitoring AI agent workflows in automation

[original] AI agents and Responses API visualized in OpenAI Traces UI - Agent workflow on the left and span details on the right
[improved] OpenAI Traces UI: displaying AI agent workflow and span details for Responses API

[original] AI agents, Responses API, function tools visualized in OpenAI Traces UI
[improved] Analysis of AI agents and function tool calls in OpenAI Traces for workflow automation

[original] AI agents, Responses API, function tools visualized in OpenAI Traces UI
[improved] OpenAI Traces: visual report of Responses API, function tool use, and agent actions

[original] AI agents, Responses API, function tools and handoffs visualized in OpenAI Traces UI
[improved] Visualization of AI agents, handoffs, and tool calls in workflow automation with OpenAI Traces

[original] AI agents, Responses API, function tools and handoffs visualized in OpenAI Traces UI - Agent workflow on the left and span details on the right
[improved] Detailed OpenAI Traces UI showing AI agent workflow and span analytics for automation

[original] Monitor Stripe disputes in dashboard
[improved] Monitoring and managing Stripe payment disputes in Stripe dashboard for automation

[original] Post by Wade Foster, Co-founder/CEO of Zapier - If you're an AI automation engineer, we'll hire you
[improved] Zapier co-founder Wade Foster's post about hiring AI automation engineers

[original] Zapier job - AI automation expert
[improved] Zapier careers: open job listing for AI automation expert engineering role

Maybe next time, I'll try giving the images directly to GPT-4.1 and see how it handles them.

That's all I have for today! Talk soon 👋

Recent posts
latestWhen "I can do this" became "I can get this done"
Start building confidence in your ability to guide AI
Improve your docs by giving your AI assistant the project's issues
See why a virtual keyboard bug calls for issue-aware docs
misc
How I use LLMs and Firecrawl to dig into company culture
Learn how I use LLMs to decode company culture from their blogs
code
Curious about the tools I use?