{"id":303,"date":"2026-07-22T14:51:12","date_gmt":"2026-07-22T14:51:12","guid":{"rendered":"https:\/\/www.lynxseo.com\/blog\/?p=303"},"modified":"2026-07-22T14:56:27","modified_gmt":"2026-07-22T14:56:27","slug":"optimizing-website-images-for-seo","status":"publish","type":"post","link":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/","title":{"rendered":"Optimizing Website Images for SEO: Top Tips &#038; Techniques"},"content":{"rendered":"<p><b><i>Quick Answer: <\/i><\/b><i><span style=\"font-weight: 400;\">Optimizing website images for SEO means serving the smallest file that still looks sharp, giving every image a clear file name and alt text, and making sure Google can actually find and index it. In practice it&#8217;s five moves: pick a modern format like WebP or AVIF, compress and resize before you upload, name the file for what it shows, write real alt text, and stop your biggest image from wrecking your load speed. Get those right and you help two things at once &#8211; your rankings and the person sitting there waiting for the page to paint.<\/span><\/i><\/p>\n<p><span style=\"font-weight: 400;\">Image SEO is the part of the job everyone knows they should handle and almost nobody actually does. People will spend three weeks arguing over a title tag and then drop a 4MB hero shot straight off their phone onto the homepage.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">That&#8217;s a bigger deal than it sounds. On the median mobile homepage, images are one of the heaviest resource types on the page, and the typical home page now ships <\/span><a href=\"https:\/\/almanac.httparchive.org\/en\/2025\/page-weight\"><span style=\"font-weight: 400;\">around 19 separate image requests<\/span><\/a><span style=\"font-weight: 400;\">. Those files are usually the difference between a page that feels instant and one that feels like it&#8217;s buffering.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This is one of the first things I learned coming up in the industry, back when we were hand-optimizing sprites to shave kilobytes. The tools have changed. The principle hasn&#8217;t: images are content, they&#8217;re a ranking signal, and they&#8217;re the fastest way to slow your own site down. Here&#8217;s how to handle them properly.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We also built the LYNX Image Optimizer to make the practical side of image SEO easier. It lets you resize, crop, and convert images to WebP directly in your browser, so you can reduce file size before uploading without sending the original image to an external server.\u00a0<\/span><\/p>\n<h2><b>Key Takeaways<\/b><\/h2>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Format First:<\/b><span style=\"font-weight: 400;\"> WebP and AVIF compress far tighter than JPEG or PNG at the same visual quality, which is the single biggest file-size win available to most sites.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Compress And Resize Before Upload:<\/b><span style=\"font-weight: 400;\"> Don&#8217;t lean on the browser to shrink a 4000px photo down to a 600px slot. Ship the size you actually display.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>File Names And Alt Text Do Double Duty:<\/b><span style=\"font-weight: 400;\"> They tell Google what the image is and make the page usable for screen readers. Descriptive beats keyword-stuffed every time.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Your Biggest Image Is A Speed Risk:<\/b><span style=\"font-weight: 400;\"> The largest image in the viewport is often your Largest Contentful Paint element, and Core Web Vitals is a ranking signal.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Help Google Find Them:<\/b><span style=\"font-weight: 400;\"> Use standard HTML <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> elements, submit an image sitemap, and add structured data so your visuals can get indexed and show up in image search.<\/span><\/li>\n<\/ul>\n<h2><b>Why Image SEO Matters and How Images Affect SEO<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Image SEO pulls three levers at the same time.<\/span><\/p>\n<h3><b>Image Search Traffic<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The first lever is <\/span><a href=\"https:\/\/developers.google.com\/search\/docs\/appearance\/google-images\"><span style=\"font-weight: 400;\">Google Images<\/span><\/a><span style=\"font-weight: 400;\"> itself. It&#8217;s a search surface in its own right, and for anything visual &#8211; products, recipes, how-to steps, real estate, gear &#8211; people search with their eyes before they read a word. Optimized images can pick up traffic from queries that never touch your blue links.<\/span><\/p>\n<h3><b>Page Speed and Core Web Vitals<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The second lever is page experience. Images are the most-requested asset type on most websites and <\/span><a href=\"https:\/\/web.dev\/articles\/browser-level-image-lazy-loading\"><span style=\"font-weight: 400;\">usually eat more bandwidth than anything else on the page<\/span><\/a><span style=\"font-weight: 400;\">. At the 90th percentile, sites push over 5MB of image data. That weight lands directly on your load speed, which lands directly on Core Web Vitals, which is a confirmed ranking signal.<\/span><\/p>\n<h3><b>Context and Topical Relevance<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The third lever is context. Search engines read the file name, the alt text, and the surrounding copy to figure out what an image shows and how it relates to the page. Good image data makes the whole page easier to understand, not just the picture.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">This matters more now than it used to. As AI-generated content floods search, original, well-labeled images are one of the signals that separate a real page from a spun-out one &#8211; the same reason we push original visuals when we talk about <\/span><a href=\"https:\/\/www.lynxseo.com\/blog\/how-to-add-value-to-ai-blog-content\/\"><span style=\"font-weight: 400;\">adding real value to AI-assisted blog content<\/span><\/a><span style=\"font-weight: 400;\">. None of this is exotic. It&#8217;s just consistently skipped. Which, if you&#8217;re competing, is good news.<\/span><\/p>\n<h2><b>Optimize Website Images With the LYNX Image Optimizer<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Knowing that you should resize, compress, and convert an image is one thing. Opening three different tools every time you publish a blog post is another. That is why we built the <\/span><b>LYNX Image Optimizer<\/b><span style=\"font-weight: 400;\">.<\/span><\/p>\n    <div id=\"lynx-imgopt-1\" class=\"lynx-imgopt\" data-ajax-url=\"https:\/\/www.lynxseo.com\/blog\/wp-admin\/admin-ajax.php\" data-nonce=\"a2af3becb4\" data-max-files=\"5\">\n\n        <link rel=\"preconnect\" href=\"https:\/\/fonts.googleapis.com\">\n        <link href=\"https:\/\/fonts.googleapis.com\/css2?family=Krona+One&family=DM+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\n        <script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\n\n        <style>\n            #lynx-imgopt-1 {\n                --lx-bg: #111827;\n                --lx-bg-alt: #25161F;\n                --lx-red: #D42E29;\n                --lx-red-dark: #a92420;\n                --lx-text: #F2F1ED;\n                --lx-text-dim: #9CA3AF;\n                --lx-border: rgba(255,255,255,0.09);\n                --lx-success: #34D399;\n                --lx-radius: 10px;\n                font-family: 'DM Mono', monospace;\n                color: var(--lx-text);\n                background: var(--lx-bg);\n                border: 1px solid var(--lx-border);\n                border-radius: var(--lx-radius);\n                padding: 28px;\n                max-width: 640px;\n                margin: 32px auto;\n                box-sizing: border-box;\n            }\n            #lynx-imgopt-1 *, #lynx-imgopt-1 *::before, #lynx-imgopt-1 *::after {\n                box-sizing: border-box;\n            }\n            #lynx-imgopt-1 h3.lx-title {\n                font-family: 'Krona One', sans-serif;\n                font-size: 15px;\n                letter-spacing: 0.06em;\n                text-transform: uppercase;\n                color: var(--lx-text);\n                margin: 0 0 4px;\n            }\n            #lynx-imgopt-1 .lx-sub {\n                color: var(--lx-text-dim);\n                font-size: 13px;\n                margin: 0 0 20px;\n                line-height: 1.5;\n            }\n            #lynx-imgopt-1 .lx-counter {\n                display: flex;\n                align-items: center;\n                gap: 8px;\n                font-size: 12px;\n                color: var(--lx-text-dim);\n                margin-bottom: 20px;\n                padding-bottom: 16px;\n                border-bottom: 1px solid var(--lx-border);\n            }\n            #lynx-imgopt-1 .lx-counter .lx-paw {\n                width: 14px;\n                height: 14px;\n                flex-shrink: 0;\n                fill: var(--lx-red);\n            }\n            #lynx-imgopt-1 .lx-counter strong {\n                color: var(--lx-text);\n                font-weight: 500;\n            }\n            #lynx-imgopt-1 .lx-dropzone {\n                border: 1.5px dashed var(--lx-border);\n                border-radius: var(--lx-radius);\n                background: var(--lx-bg-alt);\n                padding: 40px 20px;\n                text-align: center;\n                cursor: pointer;\n                transition: border-color 0.15s ease, background 0.15s ease;\n            }\n            #lynx-imgopt-1 .lx-dropzone:hover,\n            #lynx-imgopt-1 .lx-dropzone.lx-drag {\n                border-color: var(--lx-red);\n                background: #2c1a20;\n            }\n            #lynx-imgopt-1 .lx-dropzone:focus-visible {\n                outline: 2px solid var(--lx-red);\n                outline-offset: 2px;\n            }\n            #lynx-imgopt-1 .lx-dropzone svg {\n                width: 30px;\n                height: 30px;\n                fill: var(--lx-red);\n                margin-bottom: 10px;\n            }\n            #lynx-imgopt-1 .lx-dropzone p {\n                margin: 0;\n                font-size: 13px;\n                color: var(--lx-text-dim);\n            }\n            #lynx-imgopt-1 .lx-dropzone p.lx-main {\n                color: var(--lx-text);\n                font-size: 14px;\n                margin-bottom: 4px;\n            }\n            #lynx-imgopt-1 input[type=\"file\"] {\n                display: none;\n            }\n            #lynx-imgopt-1 .lx-error {\n                display: none;\n                background: rgba(212,46,41,0.12);\n                border: 1px solid var(--lx-red);\n                color: #ffb3af;\n                font-size: 13px;\n                padding: 10px 14px;\n                border-radius: 8px;\n                margin-top: 14px;\n            }\n            #lynx-imgopt-1 .lx-controls {\n                display: none;\n                margin-top: 22px;\n            }\n            #lynx-imgopt-1 .lx-selected-list {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 8px;\n                margin-bottom: 18px;\n                padding-bottom: 18px;\n                border-bottom: 1px solid var(--lx-border);\n            }\n            #lynx-imgopt-1 .lx-selected-item {\n                display: flex;\n                align-items: center;\n                gap: 8px;\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                border-radius: 7px;\n                padding: 6px 12px 6px 6px;\n            }\n            #lynx-imgopt-1 .lx-selected-item img {\n                width: 32px;\n                height: 32px;\n                object-fit: cover;\n                border-radius: 4px;\n                flex-shrink: 0;\n            }\n            #lynx-imgopt-1 .lx-selected-item span {\n                font-size: 11px;\n                color: var(--lx-text-dim);\n                white-space: nowrap;\n                overflow: hidden;\n                text-overflow: ellipsis;\n                max-width: 140px;\n            }\n            #lynx-imgopt-1 .lx-field {\n                margin-bottom: 16px;\n            }\n            #lynx-imgopt-1 label.lx-label {\n                display: block;\n                font-family: 'Krona One', sans-serif;\n                font-size: 10px;\n                letter-spacing: 0.06em;\n                text-transform: uppercase;\n                color: var(--lx-text-dim);\n                margin-bottom: 8px;\n            }\n            #lynx-imgopt-1 .lx-preset-row {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 8px;\n            }\n            #lynx-imgopt-1 .lx-preset-btn {\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text);\n                font-family: 'DM Mono', monospace;\n                font-size: 12px;\n                padding: 8px 12px;\n                border-radius: 7px;\n                cursor: pointer;\n                transition: border-color 0.15s ease, background 0.15s ease;\n            }\n            #lynx-imgopt-1 .lx-preset-btn:hover {\n                border-color: var(--lx-red);\n            }\n            #lynx-imgopt-1 .lx-preset-btn.lx-active {\n                background: var(--lx-red);\n                border-color: var(--lx-red);\n                color: #fff;\n            }\n            #lynx-imgopt-1 .lx-preset-btn:focus-visible {\n                outline: 2px solid var(--lx-red);\n                outline-offset: 2px;\n            }\n            #lynx-imgopt-1 .lx-custom-dims {\n                display: none;\n                gap: 10px;\n                margin-top: 10px;\n            }\n            #lynx-imgopt-1 .lx-custom-dims input {\n                width: 100%;\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text);\n                font-family: 'DM Mono', monospace;\n                font-size: 13px;\n                padding: 8px 10px;\n                border-radius: 7px;\n            }\n            #lynx-imgopt-1 .lx-mode-row {\n                display: flex;\n                gap: 8px;\n            }\n            #lynx-imgopt-1 .lx-mode-btn {\n                flex: 1;\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text);\n                font-family: 'DM Mono', monospace;\n                font-size: 12px;\n                padding: 9px 10px;\n                border-radius: 7px;\n                cursor: pointer;\n                text-align: center;\n            }\n            #lynx-imgopt-1 .lx-mode-btn.lx-active {\n                background: var(--lx-red);\n                border-color: var(--lx-red);\n                color: #fff;\n            }\n            #lynx-imgopt-1 .lx-mode-hint {\n                font-size: 11px;\n                color: var(--lx-text-dim);\n                line-height: 1.5;\n                margin: 8px 0 0;\n            }\n            #lynx-imgopt-1 .lx-alt-input {\n                width: 100%;\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text);\n                font-family: 'DM Mono', monospace;\n                font-size: 13px;\n                padding: 9px 12px;\n                border-radius: 7px;\n            }\n            #lynx-imgopt-1 .lx-alt-hint {\n                font-size: 11px;\n                color: var(--lx-text-dim);\n                margin-top: 6px;\n            }\n            #lynx-imgopt-1 .lx-alt-hint.lx-warn {\n                color: var(--lx-red);\n            }\n            #lynx-imgopt-1 .lx-process-btn {\n                width: 100%;\n                background: var(--lx-red);\n                border: none;\n                color: #fff;\n                font-family: 'Krona One', sans-serif;\n                font-size: 12px;\n                letter-spacing: 0.05em;\n                text-transform: uppercase;\n                padding: 13px;\n                border-radius: 8px;\n                cursor: pointer;\n                margin-top: 6px;\n                transition: background 0.15s ease;\n            }\n            #lynx-imgopt-1 .lx-process-btn:hover {\n                background: var(--lx-red-dark);\n            }\n            #lynx-imgopt-1 .lx-process-btn:disabled,\n            #lynx-imgopt-1 .lx-zip-btn:disabled {\n                opacity: 0.5;\n                cursor: not-allowed;\n            }\n            #lynx-imgopt-1 .lx-result {\n                display: none;\n                margin-top: 24px;\n                border-top: 1px solid var(--lx-border);\n                padding-top: 20px;\n            }\n            #lynx-imgopt-1 .lx-webp-note {\n                font-size: 11px;\n                color: var(--lx-text-dim);\n                line-height: 1.5;\n                margin: 0 0 16px;\n            }\n            #lynx-imgopt-1 .lx-zip-btn {\n                width: 100%;\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-red);\n                color: var(--lx-text);\n                font-family: 'Krona One', sans-serif;\n                font-size: 11px;\n                letter-spacing: 0.05em;\n                text-transform: uppercase;\n                padding: 12px;\n                border-radius: 8px;\n                cursor: pointer;\n                margin-bottom: 18px;\n                transition: background 0.15s ease, color 0.15s ease;\n            }\n            #lynx-imgopt-1 .lx-zip-btn:hover {\n                background: var(--lx-red);\n                color: #fff;\n            }\n            #lynx-imgopt-1 .lx-result-card {\n                background: var(--lx-bg-alt);\n                border: 1px solid var(--lx-border);\n                border-radius: 10px;\n                padding: 16px;\n                margin-bottom: 14px;\n            }\n            #lynx-imgopt-1 .lx-preview {\n                width: 100%;\n                border-radius: 8px;\n                border: 1px solid var(--lx-border);\n                margin-bottom: 14px;\n                display: block;\n            }\n            #lynx-imgopt-1 .lx-meter {\n                background: rgba(255,255,255,0.03);\n                border: 1px solid var(--lx-border);\n                border-radius: 10px;\n                padding: 14px 16px;\n                margin-bottom: 14px;\n            }\n            #lynx-imgopt-1 .lx-meter-top {\n                display: flex;\n                justify-content: space-between;\n                align-items: baseline;\n                margin-bottom: 8px;\n            }\n            #lynx-imgopt-1 .lx-meter-label {\n                font-family: 'Krona One', sans-serif;\n                font-size: 10px;\n                letter-spacing: 0.05em;\n                text-transform: uppercase;\n                color: var(--lx-text-dim);\n            }\n            #lynx-imgopt-1 .lx-meter-pct {\n                font-size: 20px;\n                font-weight: 500;\n                color: var(--lx-success);\n            }\n            #lynx-imgopt-1 .lx-meter-bar {\n                height: 6px;\n                background: rgba(255,255,255,0.08);\n                border-radius: 4px;\n                overflow: hidden;\n            }\n            #lynx-imgopt-1 .lx-meter-fill {\n                height: 100%;\n                width: 0%;\n                background: var(--lx-success);\n                border-radius: 4px;\n                transition: width 0.6s ease;\n            }\n            #lynx-imgopt-1 .lx-meter-sizes {\n                display: flex;\n                justify-content: space-between;\n                font-size: 11px;\n                color: var(--lx-text-dim);\n                margin-top: 8px;\n            }\n            #lynx-imgopt-1 .lx-actions {\n                display: flex;\n                flex-wrap: wrap;\n                gap: 8px;\n            }\n            #lynx-imgopt-1 .lx-action-btn {\n                flex: 1;\n                min-width: 130px;\n                background: var(--lx-bg);\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text);\n                font-family: 'DM Mono', monospace;\n                font-size: 12px;\n                padding: 10px 12px;\n                border-radius: 8px;\n                cursor: pointer;\n                text-align: center;\n            }\n            #lynx-imgopt-1 .lx-action-btn:hover {\n                border-color: var(--lx-red);\n            }\n            #lynx-imgopt-1 .lx-copied {\n                color: var(--lx-success);\n            }\n            #lynx-imgopt-1 .lx-reset-btn {\n                width: 100%;\n                background: transparent;\n                border: 1px solid var(--lx-border);\n                color: var(--lx-text-dim);\n                font-family: 'DM Mono', monospace;\n                font-size: 12px;\n                padding: 10px;\n                border-radius: 8px;\n                cursor: pointer;\n            }\n            #lynx-imgopt-1 .lx-reset-btn:hover {\n                color: var(--lx-text);\n                border-color: var(--lx-text-dim);\n            }\n            #lynx-imgopt-1 .lx-unsupported {\n                display: none;\n                font-size: 13px;\n                color: var(--lx-text-dim);\n            }\n            @media (prefers-reduced-motion: reduce) {\n                #lynx-imgopt-1 * {\n                    transition: none !important;\n                }\n            }\n        <\/style>\n\n        <h3 class=\"lx-title\">Lynx Image Optimizer<\/h3>\n        <p class=\"lx-sub\">Resize, crop, and convert up to 5 images to WebP at once, right in your browser. Nothing you upload here ever leaves your device.<\/p>\n\n        <div class=\"lx-counter\">\n            <svg class=\"lx-paw\" viewBox=\"0 0 24 24\"><path d=\"M8.5 9c1.1 0 2-1.1 2-2.5S9.6 4 8.5 4 6.5 5.1 6.5 6.5 7.4 9 8.5 9zm7 0c1.1 0 2-1.1 2-2.5S16.6 4 15.5 4s-2 1.1-2 2.5S14.4 9 15.5 9zM4.5 13c1 0 1.8-1 1.8-2.3S5.5 8.5 4.5 8.5s-1.8 1-1.8 2.2S3.5 13 4.5 13zm15 0c1 0 1.8-1 1.8-2.3S20.5 8.5 19.5 8.5s-1.8 1-1.8 2.2S18.5 13 19.5 13zM12 11.5c-2.3 0-6 2.4-6 5.4 0 1.7 1.3 2.6 3 2.6 1.2 0 2-.4 3-.4s1.8.4 3 .4c1.7 0 3-.9 3-2.6 0-3-3.7-5.4-6-5.4z\"\/><\/svg>\n            <span><strong class=\"lx-count-num\">&hellip;<\/strong> images optimized on this site<\/span>\n        <\/div>\n\n        <div class=\"lx-dropzone\" tabindex=\"0\" role=\"button\" aria-label=\"Choose up to 5 images to optimize\">\n            <svg viewBox=\"0 0 24 24\"><path d=\"M19 13v6H5v-6H3v6c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2v-6h-2zM11 2v11.17l-3.59-3.58L6 11l6 6 6-6-1.41-1.41L13 13.17V2h-2z\"\/><\/svg>\n            <p class=\"lx-main\">Click to choose images, or drag them here<\/p>\n            <p>PNG, JPG, or JPEG. Up to 5 images, 20MB each.<\/p>\n        <\/div>\n        <input type=\"file\" class=\"lx-file-input\" accept=\".png,.jpg,.jpeg,image\/png,image\/jpeg\" multiple>\n\n        <div class=\"lx-error\"><\/div>\n        <div class=\"lx-unsupported\">Your browser does not support WebP conversion in Canvas, so this tool will not work here. Try a recent version of Chrome, Firefox, Edge, or Safari.<\/div>\n\n        <div class=\"lx-controls\">\n            <div class=\"lx-selected-list\"><\/div>\n\n            <div class=\"lx-field\">\n                <label class=\"lx-label\">Output size<\/label>\n                <div class=\"lx-preset-row\">\n                    <button type=\"button\" class=\"lx-preset-btn lx-active\" data-w=\"1920\" data-h=\"1080\">1920 &times; 1080<\/button>\n                    <button type=\"button\" class=\"lx-preset-btn\" data-w=\"1200\" data-h=\"630\">1200 &times; 630 (social)<\/button>\n                    <button type=\"button\" class=\"lx-preset-btn\" data-w=\"1080\" data-h=\"1080\">1080 &times; 1080 (square)<\/button>\n                    <button type=\"button\" class=\"lx-preset-btn\" data-w=\"custom\" data-h=\"custom\">Custom<\/button>\n                <\/div>\n                <div class=\"lx-custom-dims\">\n                    <input type=\"number\" class=\"lx-custom-w\" placeholder=\"Width (px)\" min=\"1\" max=\"8000\">\n                    <input type=\"number\" class=\"lx-custom-h\" placeholder=\"Height (px)\" min=\"1\" max=\"8000\">\n                <\/div>\n            <\/div>\n\n            <div class=\"lx-field\">\n                <label class=\"lx-label\">Crop mode<\/label>\n                <div class=\"lx-mode-row\">\n                    <button type=\"button\" class=\"lx-mode-btn lx-active\" data-mode=\"crop\">Center crop to fill<\/button>\n                    <button type=\"button\" class=\"lx-mode-btn\" data-mode=\"fit\">Fit within, add padding<\/button>\n                <\/div>\n                <p class=\"lx-mode-hint\">Crop fills the exact size you picked by trimming the edges. Fit keeps the whole image visible and adds transparent padding so the output still matches that exact size.<\/p>\n            <\/div>\n\n            <button type=\"button\" class=\"lx-process-btn\">Optimize Images<\/button>\n        <\/div>\n\n        <div class=\"lx-result\">\n            <p class=\"lx-webp-note\">Converting to WebP is what shrinks the file. It trims a small amount of visual detail in the process, but the difference is hard to spot and the result is still perfectly sharp for blog use.<\/p>\n            <button type=\"button\" class=\"lx-zip-btn\">Download All as ZIP<\/button>\n            <div class=\"lx-result-list\"><\/div>\n            <button type=\"button\" class=\"lx-reset-btn\">Optimize Another Batch<\/button>\n        <\/div>\n    <\/div>\n\n    <script>\n    (function () {\n        var root = document.getElementById(\"lynx-imgopt-1\");\n        if (!root) return;\n\n        var ajaxUrl = root.getAttribute('data-ajax-url');\n        var nonce = root.getAttribute('data-nonce');\n        var MAX_FILES = parseInt(root.getAttribute('data-max-files'), 10) || 5;\n\n        var dropzone = root.querySelector('.lx-dropzone');\n        var fileInput = root.querySelector('.lx-file-input');\n        var errorBox = root.querySelector('.lx-error');\n        var unsupportedBox = root.querySelector('.lx-unsupported');\n        var controls = root.querySelector('.lx-controls');\n        var selectedList = root.querySelector('.lx-selected-list');\n        var presetBtns = root.querySelectorAll('.lx-preset-btn');\n        var customDims = root.querySelector('.lx-custom-dims');\n        var customW = root.querySelector('.lx-custom-w');\n        var customH = root.querySelector('.lx-custom-h');\n        var modeBtns = root.querySelectorAll('.lx-mode-btn');\n        var processBtn = root.querySelector('.lx-process-btn');\n        var resultBox = root.querySelector('.lx-result');\n        var resultList = root.querySelector('.lx-result-list');\n        var zipBtn = root.querySelector('.lx-zip-btn');\n        var resetBtn = root.querySelector('.lx-reset-btn');\n        var countNum = root.querySelector('.lx-count-num');\n\n        var STORAGE_KEY = 'lynxImgOptSettings';\n        var MAX_BYTES = 20 * 1024 * 1024;\n        var WEBP_QUALITY = 0.75;\n\n        var state = {\n            presetW: 1920,\n            presetH: 1080,\n            mode: 'crop',\n            items: []\n        };\n\n        (function checkSupport() {\n            var testCanvas = document.createElement('canvas');\n            testCanvas.width = 1;\n            testCanvas.height = 1;\n            var supportsWebp = testCanvas.toDataURL('image\/webp').indexOf('image\/webp') === 5;\n            if (!window.HTMLCanvasElement || !supportsWebp) {\n                unsupportedBox.style.display = 'block';\n                dropzone.style.pointerEvents = 'none';\n                dropzone.style.opacity = '0.4';\n            }\n        })();\n\n        function showError(msg) {\n            errorBox.textContent = msg;\n            errorBox.style.display = 'block';\n        }\n        function clearError() {\n            errorBox.style.display = 'none';\n            errorBox.textContent = '';\n        }\n        function formatBytes(bytes) {\n            if (bytes < 1024) return bytes + ' B';\n            if (bytes < 1024 * 1024) return (bytes \/ 1024).toFixed(1) + ' KB';\n            return (bytes \/ (1024 * 1024)).toFixed(2) + ' MB';\n        }\n        function processLabel() {\n            return state.items.length === 1 ? 'Optimize 1 Image' : 'Optimize ' + state.items.length + ' Images';\n        }\n\n        (function restoreSettings() {\n            try {\n                var saved = JSON.parse(localStorage.getItem(STORAGE_KEY) || '{}');\n                if (saved.mode === 'crop' || saved.mode === 'fit') {\n                    state.mode = saved.mode;\n                    modeBtns.forEach(function (b) {\n                        b.classList.toggle('lx-active', b.getAttribute('data-mode') === saved.mode);\n                    });\n                }\n                if (saved.presetW && saved.presetH) {\n                    var matched = false;\n                    presetBtns.forEach(function (b) {\n                        if (b.getAttribute('data-w') == saved.presetW && b.getAttribute('data-h') == saved.presetH) {\n                            presetBtns.forEach(function (x) { x.classList.remove('lx-active'); });\n                            b.classList.add('lx-active');\n                            matched = true;\n                        }\n                    });\n                    if (matched) {\n                        state.presetW = parseInt(saved.presetW, 10);\n                        state.presetH = parseInt(saved.presetH, 10);\n                    }\n                }\n            } catch (e) { }\n        })();\n\n        function saveSettings() {\n            try {\n                localStorage.setItem(STORAGE_KEY, JSON.stringify({\n                    presetW: state.presetW,\n                    presetH: state.presetH,\n                    mode: state.mode\n                }));\n            } catch (e) { }\n        }\n\n        function fetchCounter() {\n            var body = 'action=lynx_imgopt_get_counter&nonce=' + encodeURIComponent(nonce);\n            fetch(ajaxUrl, {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                body: body\n            }).then(function (r) { return r.json(); }).then(function (data) {\n                if (data && data.success) {\n                    countNum.textContent = data.data.count.toLocaleString();\n                }\n            }).catch(function () {\n                countNum.textContent = '74';\n            });\n        }\n        function incrementCounter(amount) {\n            var amt = Math.max(1, Math.min(MAX_FILES, parseInt(amount, 10) || 1));\n            var body = 'action=lynx_imgopt_increment_counter&nonce=' + encodeURIComponent(nonce) + '&amount=' + amt;\n            fetch(ajaxUrl, {\n                method: 'POST',\n                headers: { 'Content-Type': 'application\/x-www-form-urlencoded' },\n                body: body\n            }).then(function (r) { return r.json(); }).then(function (data) {\n                if (data && data.success) {\n                    countNum.textContent = data.data.count.toLocaleString();\n                }\n            }).catch(function () { });\n        }\n        fetchCounter();\n\n        if (typeof JSZip === 'undefined') {\n            zipBtn.style.display = 'none';\n        }\n\n        dropzone.addEventListener('click', function () { fileInput.click(); });\n        dropzone.addEventListener('keydown', function (e) {\n            if (e.key === 'Enter' || e.key === ' ') {\n                e.preventDefault();\n                fileInput.click();\n            }\n        });\n        ['dragenter', 'dragover'].forEach(function (evt) {\n            dropzone.addEventListener(evt, function (e) {\n                e.preventDefault();\n                dropzone.classList.add('lx-drag');\n            });\n        });\n        ['dragleave', 'drop'].forEach(function (evt) {\n            dropzone.addEventListener(evt, function (e) {\n                e.preventDefault();\n                dropzone.classList.remove('lx-drag');\n            });\n        });\n        dropzone.addEventListener('drop', function (e) {\n            if (e.dataTransfer.files && e.dataTransfer.files.length) handleFiles(e.dataTransfer.files);\n        });\n        fileInput.addEventListener('change', function (e) {\n            if (e.target.files && e.target.files.length) handleFiles(e.target.files);\n        });\n\n        presetBtns.forEach(function (btn) {\n            btn.addEventListener('click', function () {\n                presetBtns.forEach(function (b) { b.classList.remove('lx-active'); });\n                btn.classList.add('lx-active');\n                if (btn.getAttribute('data-w') === 'custom') {\n                    customDims.style.display = 'flex';\n                    state.presetW = parseInt(customW.value, 10) || 0;\n                    state.presetH = parseInt(customH.value, 10) || 0;\n                } else {\n                    customDims.style.display = 'none';\n                    state.presetW = parseInt(btn.getAttribute('data-w'), 10);\n                    state.presetH = parseInt(btn.getAttribute('data-h'), 10);\n                }\n                saveSettings();\n            });\n        });\n        [customW, customH].forEach(function (inp) {\n            inp.addEventListener('input', function () {\n                state.presetW = parseInt(customW.value, 10) || 0;\n                state.presetH = parseInt(customH.value, 10) || 0;\n            });\n        });\n\n        modeBtns.forEach(function (btn) {\n            btn.addEventListener('click', function () {\n                modeBtns.forEach(function (b) { b.classList.remove('lx-active'); });\n                btn.classList.add('lx-active');\n                state.mode = btn.getAttribute('data-mode');\n                saveSettings();\n            });\n        });\n\n        var MAGIC_BYTES = {\n            png: [0x89, 0x50, 0x4E, 0x47],\n            jpg: [0xFF, 0xD8, 0xFF]\n        };\n\n        function verifyMagicBytes(arrayBuffer) {\n            var bytes = new Uint8Array(arrayBuffer.slice(0, 4));\n            var isPng = MAGIC_BYTES.png.every(function (b, i) { return bytes[i] === b; });\n            var isJpg = MAGIC_BYTES.jpg.every(function (b, i) { return bytes[i] === b; });\n            return isPng || isJpg;\n        }\n\n        function revokeAllPreviews() {\n            state.items.forEach(function (item) {\n                if (item.previewUrl) URL.revokeObjectURL(item.previewUrl);\n            });\n        }\n\n        function renderSelectedList() {\n            selectedList.innerHTML = '';\n            state.items.forEach(function (item) {\n                var el = document.createElement('div');\n                el.className = 'lx-selected-item';\n                var img = document.createElement('img');\n                img.src = item.previewUrl;\n                img.alt = '';\n                var span = document.createElement('span');\n                span.textContent = item.name + ' (' + formatBytes(item.size) + ')';\n                el.appendChild(img);\n                el.appendChild(span);\n                selectedList.appendChild(el);\n            });\n        }\n\n        function handleFiles(fileList) {\n            var incoming = Array.prototype.slice.call(fileList);\n            var notes = [];\n\n            if (incoming.length > MAX_FILES) {\n                notes.push('Only the first ' + MAX_FILES + ' images were used. You can optimize up to ' + MAX_FILES + ' at a time.');\n                incoming = incoming.slice(0, MAX_FILES);\n            }\n\n            var allowedExt = \/\\.(png|jpe?g)$\/i;\n            var allowedMime = ['image\/png', 'image\/jpeg'];\n            var candidates = [];\n            var skipped = [];\n\n            incoming.forEach(function (file) {\n                if (!allowedExt.test(file.name) || allowedMime.indexOf(file.type) === -1) {\n                    skipped.push(file.name + ' (unsupported type)');\n                    return;\n                }\n                if (file.size > MAX_BYTES) {\n                    skipped.push(file.name + ' (too large)');\n                    return;\n                }\n                candidates.push(file);\n            });\n\n            if (!candidates.length) {\n                if (skipped.length) notes.push('Skipped: ' + skipped.join(', ') + '.');\n                showError(notes.length ? notes.join(' ') : 'Please choose a PNG, JPG, or JPEG file.');\n                return;\n            }\n\n            var checks = candidates.map(function (file) {\n                return new Promise(function (resolve) {\n                    var reader = new FileReader();\n                    reader.onload = function (e) {\n                        if (!verifyMagicBytes(e.target.result)) {\n                            skipped.push(file.name + ' (invalid file)');\n                            resolve(null);\n                            return;\n                        }\n                        resolve(file);\n                    };\n                    reader.onerror = function () {\n                        skipped.push(file.name + ' (unreadable)');\n                        resolve(null);\n                    };\n                    reader.readAsArrayBuffer(file);\n                });\n            });\n\n            Promise.all(checks).then(function (results) {\n                var validFiles = results.filter(Boolean);\n\n                if (!validFiles.length) {\n                    showError('None of the selected files could be used. Please choose valid PNG or JPEG images.');\n                    return;\n                }\n\n                revokeAllPreviews();\n                state.items = validFiles.map(function (file) {\n                    return {\n                        file: file,\n                        name: file.name,\n                        size: file.size,\n                        previewUrl: URL.createObjectURL(file),\n                        webpBlob: null,\n                        pngBlob: null,\n                        outW: 0,\n                        outH: 0\n                    };\n                });\n\n                renderSelectedList();\n\n                if (skipped.length) notes.push('Skipped: ' + skipped.join(', ') + '.');\n                if (notes.length) {\n                    showError(notes.join(' '));\n                } else {\n                    clearError();\n                }\n\n                controls.style.display = 'block';\n                resultBox.style.display = 'none';\n                processBtn.textContent = processLabel();\n            });\n        }\n\n        function processItem(item) {\n            return new Promise(function (resolve, reject) {\n                var url = URL.createObjectURL(item.file);\n                var img = new Image();\n                img.onload = function () {\n                    URL.revokeObjectURL(url);\n                    try {\n                        var canvas = document.createElement('canvas');\n                        var ctx = canvas.getContext('2d');\n\n                        if (state.mode === 'crop') {\n                            var targetW = state.presetW;\n                            var targetH = state.presetH;\n                            var imgRatio = img.width \/ img.height;\n                            var targetRatio = targetW \/ targetH;\n                            var sx, sy, sw, sh;\n                            if (imgRatio > targetRatio) {\n                                sh = img.height;\n                                sw = sh * targetRatio;\n                                sx = (img.width - sw) \/ 2;\n                                sy = 0;\n                            } else {\n                                sw = img.width;\n                                sh = sw \/ targetRatio;\n                                sx = 0;\n                                sy = (img.height - sh) \/ 2;\n                            }\n                            canvas.width = targetW;\n                            canvas.height = targetH;\n                            ctx.drawImage(img, sx, sy, sw, sh, 0, 0, targetW, targetH);\n                        } else {\n                            var scale = Math.min(state.presetW \/ img.width, state.presetH \/ img.height);\n                            if (!isFinite(scale) || scale <= 0) scale = 1;\n                            var drawW = Math.max(1, Math.round(img.width * scale));\n                            var drawH = Math.max(1, Math.round(img.height * scale));\n                            canvas.width = state.presetW;\n                            canvas.height = state.presetH;\n                            var offsetX = Math.round((state.presetW - drawW) \/ 2);\n                            var offsetY = Math.round((state.presetH - drawH) \/ 2);\n                            ctx.drawImage(img, offsetX, offsetY, drawW, drawH);\n                        }\n\n                        item.outW = canvas.width;\n                        item.outH = canvas.height;\n\n                        canvas.toBlob(function (webpBlob) {\n                            canvas.toBlob(function (pngBlob) {\n                                item.webpBlob = webpBlob;\n                                item.pngBlob = pngBlob;\n                                resolve();\n                            }, 'image\/png');\n                        }, 'image\/webp', WEBP_QUALITY);\n\n                    } catch (err) {\n                        reject(err);\n                    }\n                };\n                img.onerror = function () {\n                    URL.revokeObjectURL(url);\n                    reject(new Error('Could not load ' + item.name));\n                };\n                img.src = url;\n            });\n        }\n\n        processBtn.addEventListener('click', function () {\n            if (!state.items.length) {\n                showError('Choose at least one image first.');\n                return;\n            }\n            if (!state.presetW || !state.presetH) {\n                showError('Enter a valid custom width and height.');\n                return;\n            }\n\n            clearError();\n            processBtn.disabled = true;\n            processBtn.textContent = 'Optimizing...';\n\n            Promise.all(state.items.map(processItem)).then(function () {\n                finishProcessing();\n            }).catch(function () {\n                showError('Something went wrong while processing one or more images. Please try again.');\n                processBtn.disabled = false;\n                processBtn.textContent = processLabel();\n            });\n        });\n\n        function buildResultCard(item) {\n            var card = document.createElement('div');\n            card.className = 'lx-result-card';\n\n            var img = document.createElement('img');\n            img.className = 'lx-preview';\n            img.src = URL.createObjectURL(item.webpBlob);\n            img.alt = 'Optimized preview of ' + item.name;\n            card.appendChild(img);\n\n            var pct = Math.max(0, Math.round((1 - item.webpBlob.size \/ item.size) * 100));\n\n            var meter = document.createElement('div');\n            meter.className = 'lx-meter';\n\n            var meterTop = document.createElement('div');\n            meterTop.className = 'lx-meter-top';\n            var meterLabel = document.createElement('span');\n            meterLabel.className = 'lx-meter-label';\n            meterLabel.textContent = 'File size reduced by';\n            var meterPct = document.createElement('span');\n            meterPct.className = 'lx-meter-pct';\n            meterPct.textContent = pct + '%';\n            meterTop.appendChild(meterLabel);\n            meterTop.appendChild(meterPct);\n\n            var meterBar = document.createElement('div');\n            meterBar.className = 'lx-meter-bar';\n            var meterFill = document.createElement('div');\n            meterFill.className = 'lx-meter-fill';\n            meterFill.setAttribute('data-pct', pct);\n            meterBar.appendChild(meterFill);\n\n            var meterSizes = document.createElement('div');\n            meterSizes.className = 'lx-meter-sizes';\n            var sizeBefore = document.createElement('span');\n            sizeBefore.textContent = 'Original: ' + formatBytes(item.size);\n            var sizeAfter = document.createElement('span');\n            sizeAfter.textContent = 'Optimized: ' + formatBytes(item.webpBlob.size) + ' (' + item.outW + '\\u00d7' + item.outH + ')';\n            meterSizes.appendChild(sizeBefore);\n            meterSizes.appendChild(sizeAfter);\n\n            meter.appendChild(meterTop);\n            meter.appendChild(meterBar);\n            meter.appendChild(meterSizes);\n            card.appendChild(meter);\n\n            var altWrap = document.createElement('div');\n            altWrap.className = 'lx-field';\n            var altLabel = document.createElement('label');\n            altLabel.className = 'lx-label';\n            altLabel.textContent = 'Alt text for ' + item.name;\n            var altInputEl = document.createElement('input');\n            altInputEl.type = 'text';\n            altInputEl.className = 'lx-alt-input';\n            altInputEl.placeholder = 'Describe the image for search engines and screen readers';\n            var altHintEl = document.createElement('p');\n            altHintEl.className = 'lx-alt-hint';\n            altInputEl.addEventListener('input', function () {\n                var val = altInputEl.value.trim();\n                if (!val) {\n                    altHintEl.textContent = 'Add alt text so search engines and screen readers know what this image shows.';\n                    altHintEl.classList.add('lx-warn');\n                } else if (val.length < 8) {\n                    altHintEl.textContent = 'A little short. Describe what is actually in the image.';\n                    altHintEl.classList.add('lx-warn');\n                } else if (\/\\.(jpe?g|png|webp)$\/i.test(val) || \/^(img|image|photo|dsc)[\\-_]?\\d*$\/i.test(val)) {\n                    altHintEl.textContent = 'This looks like a filename, not a description. Try describing the image instead.';\n                    altHintEl.classList.add('lx-warn');\n                } else {\n                    altHintEl.textContent = 'Looks good.';\n                    altHintEl.classList.remove('lx-warn');\n                }\n            });\n            altWrap.appendChild(altLabel);\n            altWrap.appendChild(altInputEl);\n            altWrap.appendChild(altHintEl);\n            card.appendChild(altWrap);\n\n            var actions = document.createElement('div');\n            actions.className = 'lx-actions';\n\n            var copyBtn = document.createElement('button');\n            copyBtn.type = 'button';\n            copyBtn.className = 'lx-action-btn';\n            copyBtn.textContent = 'Copy Image';\n            copyBtn.addEventListener('click', function () {\n                if (!item.pngBlob || !navigator.clipboard || !window.ClipboardItem) {\n                    showError('Your browser does not support copying images to the clipboard. Try the download button instead.');\n                    return;\n                }\n                navigator.clipboard.write([\n                    new ClipboardItem({ 'image\/png': item.pngBlob })\n                ]).then(function () {\n                    flashLabel(copyBtn, 'Copied!');\n                }).catch(function () {\n                    showError('Could not copy the image. Try the download button instead.');\n                });\n            });\n\n            var downloadBtn = document.createElement('button');\n            downloadBtn.type = 'button';\n            downloadBtn.className = 'lx-action-btn';\n            downloadBtn.textContent = 'Download WebP';\n            downloadBtn.addEventListener('click', function () {\n                var a = document.createElement('a');\n                a.href = URL.createObjectURL(item.webpBlob);\n                a.download = item.name.replace(\/\\.(png|jpe?g)$\/i, '') + '.webp';\n                document.body.appendChild(a);\n                a.click();\n                document.body.removeChild(a);\n            });\n\n            actions.appendChild(copyBtn);\n            actions.appendChild(downloadBtn);\n            card.appendChild(actions);\n\n            return card;\n        }\n\n        function finishProcessing() {\n            processBtn.disabled = false;\n            processBtn.textContent = processLabel();\n\n            resultList.innerHTML = '';\n            state.items.forEach(function (item) {\n                resultList.appendChild(buildResultCard(item));\n            });\n\n            zipBtn.style.display = (typeof JSZip === 'undefined' || state.items.length < 2) ? 'none' : 'block';\n            zipBtn.textContent = 'Download All as ZIP (' + state.items.length + ')';\n\n            resultBox.style.display = 'block';\n            resultBox.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n\n            requestAnimationFrame(function () {\n                resultList.querySelectorAll('.lx-meter-fill').forEach(function (fillEl) {\n                    fillEl.style.width = fillEl.getAttribute('data-pct') + '%';\n                });\n            });\n\n            incrementCounter(state.items.length);\n        }\n\n        zipBtn.addEventListener('click', function () {\n            if (typeof JSZip === 'undefined' || !state.items.length) return;\n\n            var originalLabel = zipBtn.textContent;\n            zipBtn.disabled = true;\n            zipBtn.textContent = 'Zipping...';\n\n            var zip = new JSZip();\n            var usedNames = {};\n            state.items.forEach(function (item) {\n                if (!item.webpBlob) return;\n                var base = item.name.replace(\/\\.(png|jpe?g)$\/i, '');\n                var name = base + '.webp';\n                var counter = 1;\n                while (usedNames[name]) {\n                    name = base + '-' + counter + '.webp';\n                    counter++;\n                }\n                usedNames[name] = true;\n                zip.file(name, item.webpBlob);\n            });\n\n            zip.generateAsync({ type: 'blob' }).then(function (content) {\n                var a = document.createElement('a');\n                a.href = URL.createObjectURL(content);\n                a.download = 'lynx-optimized-images.zip';\n                document.body.appendChild(a);\n                a.click();\n                document.body.removeChild(a);\n                zipBtn.disabled = false;\n                zipBtn.textContent = originalLabel;\n            }).catch(function () {\n                showError('Could not create the ZIP file. Please try downloading images individually.');\n                zipBtn.disabled = false;\n                zipBtn.textContent = originalLabel;\n            });\n        });\n\n        function flashLabel(btn, text) {\n            var original = btn.textContent;\n            btn.textContent = text;\n            btn.classList.add('lx-copied');\n            setTimeout(function () {\n                btn.textContent = original;\n                btn.classList.remove('lx-copied');\n            }, 1500);\n        }\n\n        resetBtn.addEventListener('click', function () {\n            revokeAllPreviews();\n            state.items = [];\n            fileInput.value = '';\n            selectedList.innerHTML = '';\n            resultList.innerHTML = '';\n            controls.style.display = 'none';\n            resultBox.style.display = 'none';\n            processBtn.textContent = 'Optimize Images';\n            clearError();\n        });\n    })();\n    <\/script>\n    \n<p><span style=\"font-weight: 400;\">The browser-based tool handles the main preparation steps in one place. Upload a PNG, JPG, or JPEG, then choose the dimensions you need. Preset options include:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>1920 \u00d7 1080:<\/b><span style=\"font-weight: 400;\"> For large website images and presentation-style visuals<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>1200 \u00d7 630:<\/b><span style=\"font-weight: 400;\"> For social sharing and open graph images<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>1080 \u00d7 1080:<\/b><span style=\"font-weight: 400;\"> For square graphics and social posts<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Custom:<\/b><span style=\"font-weight: 400;\"> For images that need exact dimensions<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">You can then choose between a centre crop that fills the selected dimensions or a fit-within option that preserves the complete image without cropping it. The tool converts the finished image to WebP and shows you how much the file size has been reduced before you download it.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">That matters because a photograph that looks perfectly reasonable on screen can still be several megabytes larger than necessary. Converting it to WebP and resizing it to its actual display dimensions can remove most of that weight without creating an obvious drop in visual quality.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The optimizer also includes an alt text field. This does not replace adding the text to the appropriate field in WordPress, Shopify, or your CMS, but it encourages you to write the description while you can still see the image and its context.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Everything runs locally in your browser, so the images you upload do not leave your device. The result is a faster, simpler way to prepare blog images, featured images, website graphics, and social visuals before they reach your site.<\/span><\/p>\n<h2><b>Choosing the Best Image Format for SEO: WebP, AVIF, JPEG, and PNG<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Format is where the biggest, easiest wins live. Google Search <\/span><a href=\"https:\/\/developers.google.com\/search\/docs\/appearance\/google-images\"><span style=\"font-weight: 400;\">supports BMP, GIF, JPEG, PNG, WebP, SVG, and AVIF<\/span><\/a><span style=\"font-weight: 400;\">, so you&#8217;ve got room to pick the right tool.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The gap between old and new formats is not small. Looking at real images across the web, <\/span><a href=\"https:\/\/almanac.httparchive.org\/en\/2024\/media\"><span style=\"font-weight: 400;\">HTTP Archive found the median compression by format<\/span><\/a><span style=\"font-weight: 400;\"> breaks down like this: PNG spends about 3.8 bits per pixel, JPEG about 2.0, AVIF about 1.4, and WebP the tightest at 1.3. Lower bits per pixel means fewer bytes for the same image. Switching a JPEG to WebP or AVIF is often a 25-35% file-size cut with no visible quality loss.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Here&#8217;s how I think about format selection in practice:<\/span><\/p>\n<table>\n<tbody>\n<tr>\n<td><b>Format<\/b><\/td>\n<td><b>Best For<\/b><\/td>\n<td><b>Notes<\/b><\/td>\n<\/tr>\n<tr>\n<td><b>WebP<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Almost everything &#8211; photos, graphics, product shots<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Excellent compression, transparency support, near-universal browser support<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>AVIF<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Photos and hero images where every KB counts<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Best-in-class compression; slightly heavier to encode<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>JPEG<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Photographic content, universal fallback<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Still fine, but you&#8217;re leaving bytes on the table vs. WebP<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>PNG<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Logos, screenshots, anything needing crisp edges or transparency<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Large files &#8211; avoid for photos<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>SVG<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Logos, icons, simple illustrations<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Vector, resolution-independent, tiny file size<\/span><\/td>\n<\/tr>\n<tr>\n<td><b>GIF<\/b><\/td>\n<td><span style=\"font-weight: 400;\">Nothing, really<\/span><\/td>\n<td><span style=\"font-weight: 400;\">Heaviest per pixel; use a muted, looping video instead<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400;\">The practical answer to &#8220;is WebP better for SEO&#8221; is yes, indirectly &#8211; it&#8217;s not a magic ranking word, it just makes your pages lighter and faster, and that&#8217;s what Google actually measures. Serve WebP or AVIF with a JPEG fallback and you cover both modern and older browsers.<\/span><\/p>\n<h2><b>Image Compression and File Size Optimization<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Compression is where you decide how many bytes an image costs. Two things matter: the format (covered above) and the quality setting.<\/span><\/p>\n<h3><b>Picking a Quality Setting<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">For most web photos, you can drop JPEG or WebP quality to somewhere in the 75-85 range and no normal human will notice the difference on a screen. Push much lower and you start seeing mush and banding. The right amount of compression is &#8220;as much as you can get away with before it looks bad,&#8221; and that line is usually higher than people think.<\/span><\/p>\n<h3><b>Resize Before You Compress<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The bigger sin isn&#8217;t under-compressing &#8211; it&#8217;s uploading images at the wrong dimensions entirely. A 3000px-wide photo dropped into a 600px column still downloads all 3000 pixels. The browser just shrinks it on screen while the user pays for the full file. Resize to the size you actually display (plus a 2x version for retina screens), then compress. In that order.<\/span><\/p>\n<h3><b>Automating It<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">If you&#8217;re running WordPress, plugins like ShortPixel or Imagify will compress and convert to WebP on upload automatically. Shopify handles a lot of this at the platform level. Either way, the goal is the same: reduce image file size until the picture is as light as it can be without looking cheap.<\/span><\/p>\n<h2><b>Image Dimensions and Responsive Images for SEO<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Once you&#8217;ve picked a format and a quality level, you still have to serve the right size to the right device. A phone doesn&#8217;t need the same pixels as a 27-inch monitor, and shipping desktop-sized images to mobile is one of the most common reasons images slow down a website.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The fix is native HTML. The <\/span><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/HTML\/Guides\/Responsive_images\"><span style=\"font-weight: 400;\">srcset<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">sizes<\/span><span style=\"font-weight: 400;\"> attributes<\/span><\/a><span style=\"font-weight: 400;\"> let you offer the browser several versions of the same image at different widths, and the browser picks the smallest one that still looks sharp for that screen. The <\/span><span style=\"font-weight: 400;\">&lt;picture&gt;<\/span><span style=\"font-weight: 400;\"> element goes further, letting you serve different formats (AVIF, then WebP, then a JPEG fallback) or even different crops for mobile versus desktop.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">A responsive setup looks like this:<\/span><\/p>\n<p><span style=\"font-weight: 400;\">&lt;img<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0src=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">hero-800.webp<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">srcset=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">hero-400.webp <\/span><span style=\"font-weight: 400;\">400w<\/span><span style=\"font-weight: 400;\">, hero-800.webp <\/span><span style=\"font-weight: 400;\">800w<\/span><span style=\"font-weight: 400;\">, hero-1600.webp <\/span><span style=\"font-weight: 400;\">1600w<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">sizes=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">(max-width: <\/span><span style=\"font-weight: 400;\">600px<\/span><span style=\"font-weight: 400;\">) <\/span><span style=\"font-weight: 400;\">100vw<\/span><span style=\"font-weight: 400;\">, <\/span><span style=\"font-weight: 400;\">800px<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">width=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">1600<\/span><span style=\"font-weight: 400;\">&#8221; <\/span><span style=\"font-weight: 400;\">height=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">900<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">alt=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">Team assembling a delivery bike in the Burlington workshop<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">\u00a0\u00a0<\/span><span style=\"font-weight: 400;\">loading=<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">lazy<\/span><span style=\"font-weight: 400;\">&#8220;<\/span><span style=\"font-weight: 400;\">&gt;<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Two details that punch above their weight: always set <\/span><span style=\"font-weight: 400;\">width<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">height<\/span><span style=\"font-weight: 400;\"> so the browser can reserve space and avoid layout shift, and get your <\/span><span style=\"font-weight: 400;\">sizes<\/span><span style=\"font-weight: 400;\"> value right so the browser doesn&#8217;t accidentally download the biggest file anyway. For mobile image optimization specifically, responsive images are the whole ballgame &#8211; one wrong setting and phones pull the full desktop asset.<\/span><\/p>\n<h2><b>SEO Image File Names and URL Structure<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">This one is free and takes ten seconds. Before you upload, rename the file.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">IMG_4821.jpg<\/span><span style=\"font-weight: 400;\"> tells Google nothing. <\/span><span style=\"font-weight: 400;\">red-cedar-patio-furniture.jpg<\/span><span style=\"font-weight: 400;\"> tells it exactly what the image shows. Search engines read the file name as one signal for what&#8217;s in the picture, so keyword-rich image filenames &#8211; descriptive, hyphen-separated, lowercase &#8211; are a genuine (if minor) ranking input for image search.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The rules are simple:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Describe The Image:<\/b><span style=\"font-weight: 400;\"> Say what&#8217;s actually in it, not what page it lives on.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Use Hyphens, Not Underscores:<\/b><span style=\"font-weight: 400;\"> Google reads <\/span><span style=\"font-weight: 400;\">blue-suede-shoes<\/span><span style=\"font-weight: 400;\"> as three words; <\/span><span style=\"font-weight: 400;\">blue_suede_shoes<\/span><span style=\"font-weight: 400;\"> gets read as one.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Keep It Lowercase:<\/b><span style=\"font-weight: 400;\"> Avoids case-sensitivity headaches on some servers.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Don&#8217;t Stuff:<\/b> <span style=\"font-weight: 400;\">shoes-buy-shoes-cheap-shoes-online.jpg<\/span><span style=\"font-weight: 400;\"> looks like spam because it is.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Do image file names matter for SEO? Yes, but keep it in perspective. It&#8217;s a small signal that costs you nothing, so there&#8217;s no reason to skip it &#8211; but it won&#8217;t rescue a slow, badly built page on its own. The same logic applies to your overall image URL structure: clean, readable paths beat random strings.<\/span><\/p>\n<h2><b>Writing Image Alt Text for SEO and Accessibility<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Alt text is the piece everyone half-remembers and almost nobody does well. It&#8217;s the text that describes an image for screen readers and shows up when the image fails to load. Google <\/span><a href=\"https:\/\/developers.google.com\/search\/docs\/fundamentals\/seo-starter-guide\"><span style=\"font-weight: 400;\">uses it to understand what the image is about and how it relates to your page<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h3><b>The State of Alt Text (It&#8217;s Bad)<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The scale of the problem is genuinely wild. The <\/span><a href=\"https:\/\/webaim.org\/projects\/million\/\"><span style=\"font-weight: 400;\">2026 WebAIM Million report<\/span><\/a><span style=\"font-weight: 400;\"> scanned 66.6 million images across the top million home pages and found that 16.2% of them were missing alt text entirely. Worse, nearly half the images missing alt text were also links &#8211; meaning screen reader users hit a link with no idea where it goes.<\/span><\/p>\n<h3><b>How to Write Descriptive Alt Text<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Here&#8217;s the rule that clears up most confusion: write alt text for a human first, and the SEO takes care of itself. <\/span><a href=\"https:\/\/webaim.org\/techniques\/alttext\/\"><span style=\"font-weight: 400;\">WebAIM&#8217;s guidance<\/span><\/a><span style=\"font-weight: 400;\"> is to describe the content and function of the image, not to cram in keywords. If a keyword fits naturally, great. If you&#8217;re forcing it, you&#8217;re making the page worse for the exact users alt text exists to serve.<\/span><\/p>\n<table>\n<tbody>\n<tr>\n<td><b>Scenario<\/b><\/td>\n<td><b>Bad Alt Text<\/b><\/td>\n<td><b>Good Alt Text<\/b><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Product photo<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;shoes&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;Tan leather Chelsea boot, side view&#8221;<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Blog image<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;seo seo ranking google seo tips&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;Chrome DevTools showing a slow LCP image in the network waterfall&#8221;<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Decorative flourish<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;decorative swirl divider graphic&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;&#8221;<\/span><span style=\"font-weight: 400;\"> (empty, so screen readers skip it)<\/span><\/td>\n<\/tr>\n<tr>\n<td><span style=\"font-weight: 400;\">Image used as a link<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;click here&#8221;<\/span><\/td>\n<td><span style=\"font-weight: 400;\">alt=&#8221;Download the 2026 image SEO checklist (PDF)&#8221;<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><span style=\"font-weight: 400;\">A few things worth knowing:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Product Image Alt Text:<\/b><span style=\"font-weight: 400;\"> Describe the product clearly enough that someone who can&#8217;t see it could still shop it.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Blog Image Alt Text:<\/b><span style=\"font-weight: 400;\"> Describe what the graphic actually shows, not the post&#8217;s target keyword.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Decorative Images:<\/b><span style=\"font-weight: 400;\"> Use an empty <\/span><span style=\"font-weight: 400;\">alt=&#8221;&#8221;<\/span><span style=\"font-weight: 400;\"> so assistive tech skips them. That&#8217;s a real technique, not laziness.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Skip &#8220;Image Of&#8221;:<\/b><span style=\"font-weight: 400;\"> Screen readers already announce that it&#8217;s an image, so you&#8217;re wasting the listener&#8217;s time.<\/span><\/li>\n<\/ul>\n<h3><b>Alt Text vs. Title Tags and Captions<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Image title tags and captions are a separate thing from alt text. Captions sit visibly under the image and often get read more than body copy, so they&#8217;re worth using where they add context. Title attributes do almost nothing for SEO or accessibility &#8211; skip them.<\/span><\/p>\n<h2><b>Image Loading Speed and Core Web Vitals Image Optimization<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">This is where image SEO stops being about images and starts being about money, because slow pages lose visitors and Core Web Vitals feeds into rankings.<\/span><\/p>\n<h3><b>Largest Contentful Paint, Explained<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The metric to know is <\/span><a href=\"https:\/\/web.dev\/articles\/optimize-lcp\"><span style=\"font-weight: 400;\">Largest Contentful Paint<\/span><\/a><span style=\"font-weight: 400;\">, or LCP. It measures how long it takes for the biggest thing in the viewport to render, and on most pages that biggest thing is an image &#8211; your hero shot or featured image. Google wants LCP under 2.5 seconds for 75% of visits. Miss that and you&#8217;re in &#8220;needs improvement&#8221; or &#8220;poor&#8221; territory.<\/span><\/p>\n<h3><b>Why &#8220;Just Make It Smaller&#8221; Isn&#8217;t the Whole Fix<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Now here&#8217;s the part that surprises people. You&#8217;d assume the fix is always &#8220;make the image smaller.&#8221; But when Google <\/span><a href=\"https:\/\/web.dev\/blog\/common-misconceptions-lcp\"><span style=\"font-weight: 400;\">looked at field data from real page loads<\/span><\/a><span style=\"font-weight: 400;\">, it found that image download time is almost never the actual bottleneck. On the median site with poor LCP, the browser spends roughly four times as long <\/span><i><span style=\"font-weight: 400;\">waiting to start<\/span><\/i><span style=\"font-weight: 400;\"> downloading the LCP image as it does downloading it &#8211; about 1.3 seconds of dead air between the server responding and the image request even firing.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Translation: compressing your hero image helps, but the real gains often come from letting the browser find and start that image sooner. That means:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Reference the image with a standard <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tag in the HTML, not injected later by JavaScript.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Add <\/span><span style=\"font-weight: 400;\">fetchpriority=&#8221;high&#8221;<\/span><span style=\"font-weight: 400;\"> to your LCP image so the browser prioritizes it.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Never lazy-load the hero image (more on that next &#8211; it&#8217;s a classic own goal).<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Serve images from a fast host or an image CDN so the bytes travel a shorter distance.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">The encouraging news is that this is fixable. <\/span><a href=\"https:\/\/almanac.httparchive.org\/en\/2024\/performance\"><span style=\"font-weight: 400;\">HTTP Archive found<\/span><\/a><span style=\"font-weight: 400;\"> that 48% of mobile sites already serve an LCP image of 100KB or less, and the median site wastes zero kilobytes on its LCP image. The sites getting crushed are the 8% shipping LCP elements over 1MB. Don&#8217;t be in that 8%.<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Reference the image with a standard <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tag in the HTML, not injected later by JavaScript.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Add <\/span><span style=\"font-weight: 400;\">fetchpriority=&#8221;high&#8221;<\/span><span style=\"font-weight: 400;\"> to your LCP image so the browser prioritizes it.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Never lazy-load the hero image (more on that next &#8211; it&#8217;s a classic own goal).<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Serve images from a fast host or an image CDN so the bytes travel a shorter distance.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">The encouraging news is that this is fixable. HTTP Archive found that 48% of mobile sites already serve an LCP image of 100KB or less, and the median site wastes zero kilobytes on its LCP image. The sites getting crushed are the 8% shipping LCP elements over 1MB. Don&#8217;t be in that 8%.<\/span><\/p>\n<h2><b>Image Lazy Loading for SEO<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Lazy loading defers off-screen images until the user scrolls near them, so the browser isn&#8217;t downloading twenty images the visitor may never see. Since images below the fold can account for a big chunk of a page&#8217;s initial bandwidth, this is one of the cleanest speed wins available.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">You don&#8217;t need a plugin or a JavaScript library for it anymore. <\/span><a href=\"https:\/\/web.dev\/articles\/browser-level-image-lazy-loading\"><span style=\"font-weight: 400;\">Browser-level lazy loading<\/span><\/a><span style=\"font-weight: 400;\"> is built into every major browser &#8211; just add <\/span><span style=\"font-weight: 400;\">loading=&#8221;lazy&#8221;<\/span><span style=\"font-weight: 400;\"> to the <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tag.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">One rule, and it&#8217;s the one people get wrong: never lazy-load your above-the-fold images, especially your LCP element. Slapping <\/span><span style=\"font-weight: 400;\">loading=&#8221;lazy&#8221;<\/span><span style=\"font-weight: 400;\"> on your hero image tells the browser to wait on the single most important image on the page, which tanks your LCP. Lazy-load everything below the fold, load everything above it eagerly. That&#8217;s the whole strategy.<\/span><\/p>\n<h2><b>Image Indexing: Sitemaps, Structured Data, and Metadata<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">You can do everything above perfectly and still lose if Google can&#8217;t find or index your images. A few technical pieces close that gap.<\/span><\/p>\n<h3><b>Use Real HTML Image Elements<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Google <\/span><a href=\"https:\/\/developers.google.com\/search\/docs\/appearance\/google-images\"><span style=\"font-weight: 400;\">finds images in the <\/span><span style=\"font-weight: 400;\">src<\/span><span style=\"font-weight: 400;\"> attribute of the <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> element<\/span><\/a><span style=\"font-weight: 400;\"> and does not index images loaded purely through CSS backgrounds. If it&#8217;s meant to rank, it belongs in an <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tag.<\/span><\/p>\n<h3><b>Submit an Image Sitemap<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">An image sitemap hands Google a direct list of the images on your site, including ones it might not otherwise crawl. A useful detail: image sitemaps can include URLs from other domains, so if you serve images off an image CDN, you can still get them indexed &#8211; just verify the CDN domain in Search Console.<\/span><\/p>\n<h3><b>Add Structured Data for Images<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Google supports image metadata through schema.org markup and IPTC photo metadata, which can make your images eligible for the Licensable badge and give Google more context. Schema markup for images also feeds into how Google picks thumbnails &#8211; it recently confirmed it <\/span><a href=\"https:\/\/www.searchenginejournal.com\/google-clarifies-how-it-picks-thumbnails-for-search-discover\/568628\/\"><span style=\"font-weight: 400;\">uses both schema.org markup and the <\/span><span style=\"font-weight: 400;\">og:image<\/span><span style=\"font-weight: 400;\"> tag<\/span><\/a><span style=\"font-weight: 400;\"> to choose which image shows in search, and it favors large, relevant images at least 1,200px wide.<\/span><\/p>\n<h3><b>A Quick Word on EXIF Data<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The camera metadata baked into photos (location, device, timestamp) does very little for SEO, and stripping it slightly reduces file size. Keep copyright and licensing metadata, drop the rest. Just be aware that removing metadata is regulated in some jurisdictions, so check if you&#8217;re operating at scale.<\/span><\/p>\n<h2><b>Image SEO for Ecommerce, WordPress, and Shopify<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">The fundamentals are identical everywhere. What changes is the volume and the platform quirks.<\/span><\/p>\n<h3><b>Ecommerce Image Optimization<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Ecommerce image optimization is high-stakes because product images are both your conversion driver and your biggest performance liability. A category page with forty product thumbnails can be a monster if none of them are compressed or lazy-loaded. Product image SEO comes down to unique images (not manufacturer stock everyone else is using), descriptive file names and alt text per product, and aggressive compression. This is exactly the kind of thing that gets neglected on sites people inherit &#8211; and cleaning it up is a real lever. We wrote about that whole scenario in <\/span><a href=\"https:\/\/www.lynxseo.com\/blog\/inherited-bad-website-seo\/\"><span style=\"font-weight: 400;\">taking over a website with bad SEO<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Image search matters even more in visual, local, and regulated niches, where people shop with their eyes and paid ads are often restricted. A brewery living or dying on how its taproom and cans look in search is a good example &#8211; we get into that in <\/span><a href=\"https:\/\/www.lynxseo.com\/blog\/local-seo-for-breweries\/\"><span style=\"font-weight: 400;\">local SEO for breweries<\/span><\/a><span style=\"font-weight: 400;\">. And in tightly regulated spaces like cannabis, where ad channels are limited and original product imagery does heavy lifting for both rankings and AI visibility, image SEO stops being optional &#8211; which is part of why we broke it down in our guide to <\/span><a href=\"https:\/\/www.lynxseo.com\/blog\/canadian-cannabis-seo-ai-visibility\/\"><span style=\"font-weight: 400;\">Canadian cannabis SEO and AI visibility<\/span><\/a><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h3><b>WordPress Image Optimization<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">WordPress image optimization is mostly about not fighting the platform. WordPress auto-generates multiple image sizes and adds <\/span><span style=\"font-weight: 400;\">loading=&#8221;lazy&#8221;<\/span><span style=\"font-weight: 400;\"> by default. Add a compression-and-WebP plugin, make sure your theme uses proper <\/span><span style=\"font-weight: 400;\">srcset<\/span><span style=\"font-weight: 400;\"> output, and you&#8217;re most of the way there. The main trap is uploading full-res originals and letting them pile up in the media library.<\/span><\/p>\n<h3><b>Shopify Image Optimization<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Shopify image optimization is more constrained &#8211; you&#8217;re working within the platform&#8217;s rules &#8211; but Shopify serves images off its CDN, generates responsive sizes, and lets you set alt text per image right in the admin. Use it. The alt text field is sitting right there and most stores leave it blank.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Whatever the platform, if you&#8217;re rebuilding or migrating, images are one of the things that quietly break. We put together a full playbook on <\/span><a href=\"https:\/\/www.lynxseo.com\/blog\/how-to-redesign-a-website-without-losing-seo\/\"><span style=\"font-weight: 400;\">redesigning a website without losing SEO<\/span><\/a><span style=\"font-weight: 400;\"> that covers preserving image URLs and alt text through a move.<\/span><\/p>\n<h2><b>Image SEO Best Practices: The Working Checklist<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">If you want the whole thing on one page, here are the image SEO best practices we run through on client sites, in the order we do them:<\/span><\/p>\n<ul>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Pick The Format:<\/b><span style=\"font-weight: 400;\"> WebP or AVIF for photos, SVG for logos and icons, with a JPEG fallback.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Resize Before Upload:<\/b><span style=\"font-weight: 400;\"> Match the display size, plus a 2x version for retina.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Compress:<\/b><span style=\"font-weight: 400;\"> Quality around 75-85 for photos; push until just before it looks bad.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Rename The File:<\/b><span style=\"font-weight: 400;\"> Descriptive, hyphenated, lowercase, no stuffing.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Write Alt Text:<\/b><span style=\"font-weight: 400;\"> Describe content and function for a human; empty <\/span><span style=\"font-weight: 400;\">alt=&#8221;&#8221;<\/span><span style=\"font-weight: 400;\"> for decorative images.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Set Dimensions:<\/b><span style=\"font-weight: 400;\"> Always include <\/span><span style=\"font-weight: 400;\">width<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">height<\/span><span style=\"font-weight: 400;\"> to prevent layout shift.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Go Responsive:<\/b><span style=\"font-weight: 400;\"> Use <\/span><span style=\"font-weight: 400;\">srcset<\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\">sizes<\/span><span style=\"font-weight: 400;\"> so devices get the right file.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Lazy-Load Below The Fold:<\/b> <span style=\"font-weight: 400;\">loading=&#8221;lazy&#8221;<\/span><span style=\"font-weight: 400;\"> on everything except the hero.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Prioritize The LCP Image:<\/b> <span style=\"font-weight: 400;\">fetchpriority=&#8221;high&#8221;<\/span><span style=\"font-weight: 400;\">, loaded eagerly, in the HTML.<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><b>Make It Findable:<\/b><span style=\"font-weight: 400;\"> Real <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tags, an image sitemap, and structured data.<\/span><\/li>\n<\/ul>\n<p><span style=\"font-weight: 400;\">Run a page through <\/span><a href=\"https:\/\/pagespeed.web.dev\/\"><span style=\"font-weight: 400;\">PageSpeed Insights<\/span><\/a><span style=\"font-weight: 400;\"> after and it&#8217;ll flag any image that&#8217;s still dragging things down.<\/span><\/p>\n<h2><b>Conclusion<\/b><\/h2>\n<p><span style=\"font-weight: 400;\">Image SEO isn&#8217;t complicated. It&#8217;s a checklist. Format, size, compression, file name, alt text, speed, indexing &#8211; handle those and your images help your rankings instead of quietly sabotaging them. The reason it&#8217;s worth doing is that so few sites actually bother, which means it&#8217;s one of the easier places to pull ahead of competitors who are still uploading phone photos straight to their homepage.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The catch is scale. Doing this for one blog post is a five-minute job. Doing it consistently across a few hundred product pages, or fixing it retroactively on a site with thousands of neglected images, is a different kind of project &#8211; the kind that eats a marketing team&#8217;s week and never quite gets finished.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">That&#8217;s the work we do at<\/span><a href=\"https:\/\/www.lynxseo.com\/\"> <span style=\"font-weight: 400;\">LYNX SEO<\/span><\/a><span style=\"font-weight: 400;\">. If you&#8217;d rather spend your time running the business than renaming image files and chasing Core Web Vitals scores, that&#8217;s exactly the kind of thing we handle &#8211; at scale, and built to hold up.<\/span><a href=\"https:\/\/www.lynxseo.com\/\"> <span style=\"font-weight: 400;\">Get in touch<\/span><\/a><span style=\"font-weight: 400;\"> and we&#8217;ll take a look at your site.<\/span><\/p>\n<h2><b>Frequently Asked Questions<\/b><\/h2>\n<h3><b>What Is the LYNX Image Optimizer?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">The LYNX Image Optimizer is a browser-based tool for resizing, cropping, and converting PNG, JPG, and JPEG files to WebP. You can select common website and social dimensions, enter a custom size, choose whether to crop or preserve the complete image, and preview the file-size reduction before downloading it. The tool also provides a space to prepare descriptive alt text. Because the processing happens inside your browser, the original image never leaves your device.<\/span><\/p>\n<h3><b>Why Is Image SEO Important?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Because images are usually the heaviest thing on your page and one of Google&#8217;s clearest signals for what a page is about. Optimized images load faster (helping Core Web Vitals and rankings), can pull traffic from Google Images, and make your site usable for people relying on screen readers. Skipping image SEO leaves easy wins on the table and often slows your whole site down.<\/span><\/p>\n<h3><b>How Do Images Affect SEO?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Three ways. They influence page speed and Core Web Vitals, which are ranking factors. They provide context through file names, alt text, and captions that help Google understand the page. And they can rank directly in image search, opening a traffic channel your text content can&#8217;t reach.<\/span><\/p>\n<h3><b>What Is the Best Image Format for SEO?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">For most photos and graphics, WebP or AVIF, because they compress much tighter than JPEG or PNG at the same quality &#8211; <\/span><a href=\"https:\/\/almanac.httparchive.org\/en\/2024\/media\"><span style=\"font-weight: 400;\">HTTP Archive data<\/span><\/a><span style=\"font-weight: 400;\"> shows WebP and AVIF using roughly a third fewer bits per pixel than PNG. Use SVG for logos and icons, and keep a JPEG fallback for older browsers. There&#8217;s no format that &#8220;ranks better&#8221; on its own; the win is smaller files and faster pages.<\/span><\/p>\n<h3><b>How Do You Optimize Images for Google?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Resize and compress before upload, use a modern format, give each image a descriptive file name and real alt text, serve responsive versions with <\/span><span style=\"font-weight: 400;\">srcset<\/span><span style=\"font-weight: 400;\">, lazy-load below-the-fold images, and make sure Google can find them through standard <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tags, an image sitemap, and structured data.<\/span><\/p>\n<h3><b>Does Image Size Affect SEO?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Yes. Oversized image files slow your page down, which hurts Largest Contentful Paint and Core Web Vitals &#8211; both tied to rankings and user experience. The fix is serving the dimensions you actually display and compressing the file. <\/span><a href=\"https:\/\/web.dev\/blog\/common-misconceptions-lcp\"><span style=\"font-weight: 400;\">Google&#8217;s field data<\/span><\/a><span style=\"font-weight: 400;\"> also shows that <\/span><i><span style=\"font-weight: 400;\">when<\/span><\/i><span style=\"font-weight: 400;\"> the browser starts loading the image often matters as much as its size.<\/span><\/p>\n<h3><b>Is WebP Better for SEO?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Indirectly, yes. WebP isn&#8217;t a ranking keyword, but it produces smaller files than JPEG or PNG at equal quality, and smaller files mean faster pages, which Google does reward. Serve it with a JPEG fallback and you get the speed benefit across all browsers.<\/span><\/p>\n<h3><b>How Much Should You Compress Images?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">For photographic content, a quality setting around 75-85 for JPEG or WebP usually cuts file size hard with no visible loss on screen. Push lower and you risk visible artifacts and banding. The right level is the most compression you can apply before the image starts looking degraded.<\/span><\/p>\n<h3><b>Do Image File Names Matter for SEO?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">They&#8217;re a small but real signal. Descriptive, hyphenated, lowercase file names like <\/span><span style=\"font-weight: 400;\">standing-desk-walnut-top.jpg<\/span><span style=\"font-weight: 400;\"> help Google understand image content for image search. It won&#8217;t make or break your rankings, but it costs nothing, so there&#8217;s no reason to leave images named <\/span><span style=\"font-weight: 400;\">IMG_0492.jpg<\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h3><b>Should Every Image Have Alt Text?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Every meaningful image should. Alt text makes images accessible to screen reader users and gives Google context. The exception is purely decorative images, which should get an empty <\/span><span style=\"font-weight: 400;\">alt=&#8221;&#8221;<\/span><span style=\"font-weight: 400;\"> so assistive technology skips them. Write it to describe the image for a person, not to stuff keywords.<\/span><\/p>\n<h3><b>How Do I Get Images Indexed by Google?<\/b><\/h3>\n<p><span style=\"font-weight: 400;\">Reference images with standard HTML <\/span><span style=\"font-weight: 400;\">&lt;img&gt;<\/span><span style=\"font-weight: 400;\"> tags (Google doesn&#8217;t index CSS background images), <\/span><a href=\"https:\/\/developers.google.com\/search\/docs\/appearance\/google-images\"><span style=\"font-weight: 400;\">submit an image sitemap<\/span><\/a><span style=\"font-weight: 400;\"> so Google knows they exist, and add structured data for extra context. Then confirm they&#8217;re being crawled by checking the indexing reports in Google Search Console.<\/span><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Quick Answer: Optimizing website images for SEO means serving the smallest file that still looks sharp, giving every image a clear file name and alt text, and making sure Google&#8230;<\/p>\n","protected":false},"author":6,"featured_media":313,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[11],"tags":[40,37,41,39,38,36],"class_list":["post-303","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-design-development","tag-image-converter","tag-image-optimization","tag-image-optimizer","tag-image-seo","tag-optimizing-images-for-seo","tag-website-design"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Optimizing Website Images for SEO: Top Tips &amp; Techniques<\/title>\n<meta name=\"description\" content=\"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here&#039;s the exact checklist we use to fix that...\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Optimizing Website Images for SEO: Top Tips &amp; Techniques\" \/>\n<meta property=\"og:description\" content=\"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here&#039;s the exact checklist we use to fix that...\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/\" \/>\n<meta property=\"og:site_name\" content=\"LYNX SEO\" \/>\n<meta property=\"article:published_time\" content=\"2026-07-22T14:51:12+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-07-22T14:56:27+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2400\" \/>\n\t<meta property=\"og:image:height\" content=\"1256\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Michelle Terry\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Michelle Terry\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"22 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/\"},\"author\":{\"name\":\"Michelle Terry\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#\\\/schema\\\/person\\\/8170bc5e649a281217d2d561559380c7\"},\"headline\":\"Optimizing Website Images for SEO: Top Tips &#038; Techniques\",\"datePublished\":\"2026-07-22T14:51:12+00:00\",\"dateModified\":\"2026-07-22T14:56:27+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/\"},\"wordCount\":4463,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Optimizing-Website-Images-for-SEO.webp\",\"keywords\":[\"Image converter\",\"image optimization\",\"Image Optimizer\",\"Image SEO\",\"Optimizing images for SEO\",\"Website design\"],\"articleSection\":[\"Design &amp; Development\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/\",\"url\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/\",\"name\":\"Optimizing Website Images for SEO: Top Tips & Techniques\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Optimizing-Website-Images-for-SEO.webp\",\"datePublished\":\"2026-07-22T14:51:12+00:00\",\"dateModified\":\"2026-07-22T14:56:27+00:00\",\"description\":\"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here's the exact checklist we use to fix that...\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Optimizing-Website-Images-for-SEO.webp\",\"contentUrl\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/Optimizing-Website-Images-for-SEO.webp\",\"width\":2400,\"height\":1256,\"caption\":\"The LYNX SEO cat has been hard at work optimizing images for the delight of the internet\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/optimizing-website-images-for-seo\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Optimizing Website Images for SEO: Top Tips &#038; Techniques\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/\",\"name\":\"LYNX SEO Blog\",\"description\":\"Our Blog\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#organization\",\"name\":\"LYNX SEO\",\"url\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/red-white-1000.png\",\"contentUrl\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/03\\\/red-white-1000.png\",\"width\":1000,\"height\":1000,\"caption\":\"LYNX SEO\"},\"image\":{\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.linkedin.com\\\/company\\\/lynx-seo\\\/\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.lynxseo.com\\\/blog\\\/#\\\/schema\\\/person\\\/8170bc5e649a281217d2d561559380c7\",\"name\":\"Michelle Terry\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g\",\"caption\":\"Michelle Terry\"}}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Optimizing Website Images for SEO: Top Tips & Techniques","description":"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here's the exact checklist we use to fix that...","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/","og_locale":"en_US","og_type":"article","og_title":"Optimizing Website Images for SEO: Top Tips & Techniques","og_description":"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here's the exact checklist we use to fix that...","og_url":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/","og_site_name":"LYNX SEO","article_published_time":"2026-07-22T14:51:12+00:00","article_modified_time":"2026-07-22T14:56:27+00:00","og_image":[{"width":2400,"height":1256,"url":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp","type":"image\/webp"}],"author":"Michelle Terry","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Michelle Terry","Est. reading time":"22 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#article","isPartOf":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/"},"author":{"name":"Michelle Terry","@id":"https:\/\/www.lynxseo.com\/blog\/#\/schema\/person\/8170bc5e649a281217d2d561559380c7"},"headline":"Optimizing Website Images for SEO: Top Tips &#038; Techniques","datePublished":"2026-07-22T14:51:12+00:00","dateModified":"2026-07-22T14:56:27+00:00","mainEntityOfPage":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/"},"wordCount":4463,"commentCount":0,"publisher":{"@id":"https:\/\/www.lynxseo.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp","keywords":["Image converter","image optimization","Image Optimizer","Image SEO","Optimizing images for SEO","Website design"],"articleSection":["Design &amp; Development"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/","url":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/","name":"Optimizing Website Images for SEO: Top Tips & Techniques","isPartOf":{"@id":"https:\/\/www.lynxseo.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#primaryimage"},"image":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#primaryimage"},"thumbnailUrl":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp","datePublished":"2026-07-22T14:51:12+00:00","dateModified":"2026-07-22T14:56:27+00:00","description":"Most sites quietly sabotage their own speed and rankings with unoptimized images. Here's the exact checklist we use to fix that...","breadcrumb":{"@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#primaryimage","url":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp","contentUrl":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/07\/Optimizing-Website-Images-for-SEO.webp","width":2400,"height":1256,"caption":"The LYNX SEO cat has been hard at work optimizing images for the delight of the internet"},{"@type":"BreadcrumbList","@id":"https:\/\/www.lynxseo.com\/blog\/optimizing-website-images-for-seo\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lynxseo.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Optimizing Website Images for SEO: Top Tips &#038; Techniques"}]},{"@type":"WebSite","@id":"https:\/\/www.lynxseo.com\/blog\/#website","url":"https:\/\/www.lynxseo.com\/blog\/","name":"LYNX SEO Blog","description":"Our Blog","publisher":{"@id":"https:\/\/www.lynxseo.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lynxseo.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.lynxseo.com\/blog\/#organization","name":"LYNX SEO","url":"https:\/\/www.lynxseo.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lynxseo.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/03\/red-white-1000.png","contentUrl":"https:\/\/www.lynxseo.com\/blog\/wp-content\/uploads\/2026\/03\/red-white-1000.png","width":1000,"height":1000,"caption":"LYNX SEO"},"image":{"@id":"https:\/\/www.lynxseo.com\/blog\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.linkedin.com\/company\/lynx-seo\/"]},{"@type":"Person","@id":"https:\/\/www.lynxseo.com\/blog\/#\/schema\/person\/8170bc5e649a281217d2d561559380c7","name":"Michelle Terry","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/9bf561550b9404ed93975cfe873fa1716827d05e282971d1f3659ac838a65791?s=96&d=mm&r=g","caption":"Michelle Terry"}}]}},"_links":{"self":[{"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/posts\/303","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/comments?post=303"}],"version-history":[{"count":3,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/posts\/303\/revisions"}],"predecessor-version":[{"id":311,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/posts\/303\/revisions\/311"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/media\/313"}],"wp:attachment":[{"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/media?parent=303"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/categories?post=303"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lynxseo.com\/blog\/wp-json\/wp\/v2\/tags?post=303"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}