How to Turn Performance Audits into AI Fix Prompts with a DevTools Extension — Opportunihub
Course Remote

How to Turn Performance Audits into AI Fix Prompts with a DevTools Extension

Olamilekan Lamidi · Remote

At a glance

Type
Course
Organisation
Olamilekan Lamidi
Location
Remote
Work mode
Remote
Deadline
Rolling / not stated
Posted
22 Jun 2026

About this course

<p>Performance tools are good at showing you what's slow. They can tell you that your Largest Contentful Paint is 4.2 seconds, your JavaScript bundle is too large, or an image below the fold is loading too early.</p> <p>But they usually don't tell you the next info you need as a developer: <strong>What should I ask my coding agent to change?</strong></p> <p>AI coding agents can help you fix performance issues, but they need clear context. If you type "make this site faster", you'll often get broad advice. If you give the agent the metric, the affected resource, the likely cause, and the files to inspect first, you have a much better chance of getting a useful patch.</p> <p>In this tutorial, you'll learn how to turn a browser performance finding into a structured AI fix prompt. You'll also see how to add a "Copy AI fix prompt" button to a Chrome DevTools extension.</p> <p>I'll use PerfLens, a Chrome DevTools extension I built, as the example. But the same pattern works with any tool that can collect performance data.</p> <h2 id="heading-what-you-will-build">What You Will Build</h2> <p>You'll build a small pipeline that looks like this:</p> <pre><code class="language-text">Performance finding -&gt; Structured issue object -&gt; AI fix prompt -&gt; Clipboard -&gt; Coding agent -&gt; Code change -&gt; Re-run audit </code></pre> <p>By the end, you will have:</p> <ul> <li><p>A <code>Finding</code> type for storing audit results</p> </li> <li><p>A prompt builder function</p> </li> <li><p>A copy-to-clipboard function</p> </li> <li><p>A DevTools panel button that copies the generated prompt</p> </li> <li><p>A simple way to verify whether the fix worked</p> </li> </ul> <h2 id="heading-prerequisites">Prerequisites</h2> <p>To follow along, you should understand:</p> <ul> <li><p>Basic JavaScript or TypeScript</p> </li> <li><p>Basic browser extension concepts</p> </li> <li><p>How Chrome DevTools panels work at a high level</p> </li> <li><p>How to use an AI coding agent such as Cursor, Claude Code, GitHub Copilot, or a similar tool</p> </li> </ul> <p>You don't need to build a full performance auditing engine for this tutorial. The focus is the handoff between a performance tool and a coding agent.</p> <h2 id="heading-table-of-contents">Table of Contents</h2> <ul> <li><p><a href="#heading-why-performance-reports-are-hard-to-turn-into-code-changes">Why Performance Reports Are Hard to Turn into Code Changes</a></p> </li> <li><p><a href="#heading-what-an-ai-fix-prompt-should-include">What an AI Fix Prompt Should Include</a></p> </li> <li><p><a href="#heading-how-to-store-a-performance-finding-as-structured-data">How to Store a Performance Finding as Structured Data</a></p> </li> <li><p><a href="#heading-how-to-choose-the-most-important-finding">How to Choose the Most Important Finding</a></p> </li> <li><p><a href="#heading-how-to-build-the-ai-fix-prompt">How to Build the AI Fix Prompt</a></p> </li> <li><p><a href="#heading-how-to-copy-the-prompt-to-the-clipboard">How to Copy the Prompt to the Clipboard</a></p> </li> <li><p><a href="#heading-how-to-add-the-button-to-a-devtools-panel">How to Add the Button to a DevTools Panel</a></p> </li> <li><p><a href="#heading-how-to-verify-the-fix">How to Verify the Fix</a></p> </li> <li><p><a href="#heading-how-this-fits-alongside-lighthouse">How This Fits Alongside Lighthouse</a></p> </li> <li><p><a href="#heading-conclusion">Conclusion</a></p> </li> </ul> <h2 id="heading-why-performance-reports-are-hard-to-turn-into-code-changes">Why Performance Reports Are Hard to Turn into Code Changes</h2> <p>A performance score is a symptom. For example, a report might say:</p> <pre><code class="language-text">Largest Contentful Paint: 4.2 seconds </code></pre> <p>That number matters, but it doesn't tell you where the fix lives.</p> <p>The cause might be:</p> <ul> <li><p>A large hero image</p> </li> <li><p>A render-blocking script</p> </li> <li><p>Too much JavaScript on the initial route</p> </li> <li><p>A slow API request</p> </li> <li><p>Missing image dimensions that cause layout shift</p> </li> </ul> <p>As a developer, you usually have to translate the report into a code-level task.</p> <p>That translation step takes time. It's also the step where a coding agent can help most, if you give it enough context.</p> <p>Instead of asking your agent to "make the site faster", you can give it a focused brief:</p> <pre><code class="language-text">The homepage has a 258.1 KB image affecting load performance. Inspect the hero section and image component first. Resize or compress the image without changing the layout. Then explain how to verify the improvement. </code></pre> <p>This is easier for the agent to act on because it points to one specific problem.</p> <h2 id="heading-what-an-ai-fix-prompt-should-include">What an AI Fix Prompt Should Include</h2> <p>A good AI fix prompt should read like a short engineering brief.</p> <p>It should include:</p> <ul> <li><p>The performance problem</p> </li> <li><p>The measured evidence</p> </li> <li><p>The affected page or resource</p> </li> <li><p>The likely cause</p> </li> <li><p>The files or patterns to inspect first</p> </li> <li><p>A recommended fix</p> </li> <li><p>Constraints for the change</p> </li> <li><p>Verification steps</p> </li> </ul> <p>Here is an example prompt:</p> <pre><code class="language-text">You are helping optimize a Next.js app in a production build. Problem: Image is 258.1 KB and may be slowing down the page. Evidence: Image size = 258.1 KB Page: http://localhost:3000 Affected resource: http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&amp;w=3840&amp;q=75 Likely cause: The page is loading an image that is larger than needed for its rendered size. Inspect first: - app/page.tsx or pages/index.tsx - components/**/*.{tsx,jsx} - next.config.js - the hero section or image component Recommended fix: Resize or compress the image, use an appropriate modern format, and keep explicit width and height values so the layout does not shift. Constraints: - Keep the change local to the route or component causing the issue. - Do not add a new dependency unless there is no reasonable alternative. - Explain the change before applying it. After the change: - Re-run the performance audit. - Confirm the image transfer size is lower. - Confirm the layout still looks correct. </code></pre> <p>This prompt is specific. It tells the agent what happened, where to look, what to change, and how to check the result.</p> <p>That's the core idea behind an AI patch brief.</p> <p>Here is what that looks like inside PerfLens. A single performance finding is rendered as an AI patch brief, with the measured value, the affected resource, and the generated prompt gathered in one place. The "Copy AI fix prompt" button then hands the whole brief off to your coding agent in one click.</p> <img src="https://cdn.hashnode.com/uploads/covers/69daa79bc8e5007ddbe1b633/2f5fa3ec-f3c1-44d0-b53b-3ce37fac65e9.png" alt="PerfLens screenshot" style="display:block;margin:0 auto" width="600" height="400" loading="lazy"> <h2 id="heading-how-to-store-a-performance-finding-as-structured-data">How to Store a Performance Finding as Structured Data</h2> <p>Before you can build a prompt, you need to store the performance issue as data.</p> <p>Here is a simple TypeScript type:</p> <pre><code class="language-typescript">type Finding = { id: string; title: string; metric: string; measured: string; budget?: string; resource?: string; likelyCause: string; recommendedFix: string; inspectFirst: string[]; severity: "low" | "medium" | "high"; }; </code></pre> <p>Each field has a job:</p> <ul> <li><p><code>id</code> identifies the type of issue.</p> </li> <li><p><code>title</code> gives the human-readable summary.</p> </li> <li><p><code>metric</code> names the measurement.</p> </li> <li><p><code>measured</code> stores the actual value.</p> </li> <li><p><code>budget</code> stores the target value, if you have one.</p> </li> <li><p><code>resource</code> stores the affected URL, file, or asset.</p> </li> <li><p><code>likelyCause</code> explains why the issue may be happening.</p> </li> <li><p><code>recommendedFix</code> gives the agent a direction.</p> </li> <li><p><code>inspectFirst</code> points the agent toward likely files.</p> </li> <li><p><code>severity</code> helps you decide what to show first.</p> </li> </ul> <p>Here is an example finding for an oversized image:</p> <pre><code class="language-typescript">const finding: Finding = { id: "image-weight", title: "Image is 258.1 KB and may be slowing down the page", metric: "Image size", measured: "258.1 KB", resource: "http://localhost:3000/_next/image?url=%2Fhome%2Four_story.webp&amp;w=3840&amp;q=75", likelyCause: "The page is loading an image that is larger than needed for its rendered size.", recommendedFix: "Resize or compress the image, use an appropriate modern format, and keep explicit width and height values.", inspectFirst: [ "app/page.tsx or pages/index.tsx", "components/**/*.{tsx,jsx}", "next.config.js", "the hero section or image component", ], severity: "high", }; </code></pre> <p>At this stage, you aren't doing anything with AI yet. You're only turning a performance result into a clean object.</p> <p>That object gives you something reliable to transform into a prompt later.</p> <h2 id="heading-how-to-choose-the-most-important-finding">How to Choose the Most Important Finding</h2> <p>You should avoid sending ten unrelated performance issues to an agent at once.</p> <p>A large prompt with many issues can lead to a large patch. That makes the result harder to review.</p> <p>A better approach is to generate one prompt per finding.</p> <p>You can start with a simple severity score:</p> <pre><code class="language-typescript">function scoreFinding(finding: Finding): number { const severityWeight = { low: 1, medium: 2, high: 3, }; return severityWeight[finding.severity]; } </code></pre> <p>Then you can sort findings by score:</p> <pre><code class="language-typescript">function sortFindings(findings: Finding[]): Finding[] { return [...findings].sort( (a, b) =&gt; scoreFinding(b) - scoreFinding(a) ); } </code></pre> <p>This is a simple version, but it's enough to get started.</p> <p>Later, you can improve the score by considering:</p> <ul> <li><p>How far the metric is over budget</p> </li> <li><p>Whether the issue affects Largest Contentful Paint</p> </li> <li><p>Whether the issue affects layout shift or interaction delay</p> </li> <li><p>Whether the affected resource is part of the first page load</p> </li> <li><p>How confident you are in the recommended fix</p> </li> </ul> <p>The goal isn't to create a perfect scoring system. The goal is to help you focus on one high-impact issue at a time.</p> <h2 id="heading-how-to-build-the-ai-fix-prompt">How to Build the AI Fix Prompt</h2> <p>Once you have a <code>Finding</code>, building the prompt becomes a string formatting task.</p> <p>You also need a small amount of page context:</p> <pre><code class="language-typescript">type PageContext = { framework: string; mode: string; pageUrl: string; }; </code></pre> <p>Page context is a few facts about the page the finding came from: the framework the app uses, whether it's a development or production build, and the URL being audited.</p> <p>The finding tells the agent <em>what</em> is slow. The page context tells it <em>where</em> the fix will land and <em>how</em> the code is built. This matters because the same problem is fixed differently from one stack to the next. An oversized image is handled through <code>next/image</code> and <code>next.config.js</code> in Next.js, but through other files and conventions elsewhere. The <code>mode</code> field also hints whether production optimizations should already be in place.</p> <p>Giving the agent this up front means it spends less effort guessing about your setup and more on the actual fix.</p> <p>Then you can create a prompt builder:</p> <pre><code class="language-typescript">function buildFixPrompt(finding: Finding, ctx: PageContext): string { const lines = [ "You are helping optimize a " + ctx.framework + " app in a " + ctx.mode + " build.", "", "Problem: " + finding.title, "Evidence: " + finding.metric + " = " + finding.measured + (finding.budget ? " (budget: " + finding.budget + ")" : ""), "Page: " + ctx.pageUrl, ]; if (finding.resource) { lines.push("Affected resource: " + finding.resource); } lines.push( "", "Likely cause:", finding.likelyCause, "", "Inspect first:", ...finding.inspectFirst.map((file) =&gt; "- " + file), "", "Recommended fix:", finding.recommendedFix, "", "Constraints:", "- Keep the change local to the route or component causing the measured cost.", "- Do not add new dependencies unless there is no reasonable alternative.", "- Explain the change before applying it.", "", "After the change:", "- Re-run the performance audit.", "- Confirm the measured issue improved.", "- Check that the UI still works correctly.", ); return lines.join("\n"); } </code></pre> <p>You can call it like this:</p> <pre><code class="language-typescript">const pageContext: PageContext = { framework: "Next.js", mode: "production", pageUrl: "http://localhost:3000", }; const prompt = buildFixPrompt(finding, pageContext); </code></pre> <p>The output is a prompt you can paste into a coding agent.</p> <p>The <code>framework</code> field is especially useful. If the agent knows the app uses Next.js, it can look for files such as <code>app/page.tsx</code>, <code>pages/index.tsx</code>, <code>next.config.js</code>, and image usage through <code>next/image</code>.</p> <h2 id="heading-how-to-copy-the-prompt-to-the-clipboard">How to Copy the Prompt to the Clipboard</h2> <p>The safest integration is clipboard-first.</p> <p>Many coding agents and editors support different launch methods. Some support deep links. Some run in the terminal. Some live inside an editor. But every agent can accept pasted text.</p> <p>Here's a small copy function:</p> <pre><code class="language-typescript">async function copyPrompt(prompt: string): Promise&lt;void&gt; { await navigator.clipboard.writeText(prompt); } </code></pre> <p>In a browser extension UI, call this from a user action such as a button click:</p> <pre><code class="language-typescript">copyButton.addEventListener("click", async () =&gt; { const prompt = buildFixPrompt(finding, pageContext); await copyPrompt(prompt); copyButton.textContent = "Prompt copied"; }); </code></pre> <p>You can also try to open an editor after copying the prompt:</p> <pre><code class="language-typescript">type AgentTarget = "cursor" | "vscode" | "copy-only"; async function sendToAgent( prompt: string, target: AgentTarget ): Promise&lt;void&gt; { await navigator.clipboard.writeText(prompt); if (target === "cursor") { window.location.href = "cursor://"; return; } if (target === "vscode") { window.location.href = "vscode://"; return; } } </code></pre> <p>This doesn't paste the prompt into the agent automatically. It only copies the prompt and tries to open the selected tool.</p> <p>That is a useful limitation. It keeps the workflow predictable and lets you review the prompt before sending it.</p> <h2 id="heading-how-to-add-the-button-to-a-devtools-panel">How to Add the Button to a DevTools Panel</h2> <p>If you build this into a Chrome extension, you can expose it inside a DevTools panel.</p> <p>First, register a DevTools page in your <code>manifest.json</code> file:</p> <pre><code class="language-json">{ "manifest_version": 3, "name": "PerfLens", "version": "1.0.0", "devtools_page": "devtools.html", "permissions": ["clipboardWrite", "activeTab", "scripting"] } </code></pre> <p>Then create the panel from your DevTools script:</p> <pre><code class="language-typescript">chrome.devtools.panels.create( "PerfLens", "icons/icon-32.png", "panel.html" ); </code></pre> <p>Inside the panel, render each finding with a button:</p> <pre><code class="language-typescript">function renderFinding( finding: Finding, ctx: PageContext ): HTMLElement { const item = document.createElement("article"); const title = document.createElement("h3"); const button = document.createElement("button"); title.textContent = finding.title; button.textContent = "Copy AI fix prompt"; button.addEventListener("click", async () =&gt; { const prompt = buildFixPrompt(finding, ctx); await sendToAgent(prompt, "copy-only"); button.textContent = "Prompt copied"; }); item.append(title, button); return item; } </code></pre> <p>The important part is the button handler.</p> <p>When you click the button, your extension:</p> <ol> <li><p>Builds a prompt from the performance finding.</p> </li> <li><p>Copies the prompt to the clipboard.</p> </li> <li><p>Shows feedback that the prompt was copied.</p> </li> </ol> <p>You can then paste the prompt into your coding agent and review the suggested patch.</p> <h2 id="heading-how-to-verify-the-fix">How to Verify the Fix</h2> <p>An AI-generated patch is only useful if the metric improves.</p> <p>After the agent suggests a change, you should:</p> <ol> <li><p>Review the code diff.</p> </li> <li><p>Run the app locally.</p> </li> <li><p>Reload the page.</p> </li> <li><p>Re-run the performance audit.</p> </li> <li><p>Compare the new measurement with the original one.</p> </li> </ol> <p>For the image example, you would check:</p> <ul> <li><p>Did the image transfer size go down?</p> </li> <li><p>Does the image still look sharp enough?</p> </li> <li><p>Did the page layout stay stable?</p> </li> <li><p>Did Largest Contentful Paint improve?</p> </li> <li><p>Did the change affect any other route?</p> </li> </ul> <p>This creates a simple loop:</p> <pre><code class="language-text">Measure -&gt; Prompt -&gt; Patch -&gt; Measure again </code></pre> <p>You shouldn't treat the agent's answer as the final authority. The browser measurement is the final authority.</p> <h2 id="heading-how-this-fits-alongside-lighthouse">How This Fits Alongside Lighthouse</h2> <p>Lighthouse is still useful. It gives you a detailed lab audit and a consistent score. This workflow solves a different problem.</p> <p>Lighthouse helps you answer:</p> <pre><code class="language-text">How does this page perform under controlled conditions? </code></pre> <p>An AI patch brief helps you answer:</p> <pre><code class="language-text">What should I ask my coding agent to fix right now? </code></pre> <p>You can use both.</p> <p>Use Lighthouse for scoring, regression tracking, and deeper audits. Use an AI prompt workflow when you want to move from a specific finding to a code change faster.</p> <h2 id="heading-a-note-on-privacy">A Note on Privacy</h2> <p>AI fix prompts can include URLs, resource names, routes, filenames, and implementation details.</p> <p>Before you paste a prompt into a cloud-based coding agent, check that it doesn't include:</p> <ul> <li><p>Access tokens</p> </li> <li><p>Private customer data</p> </li> <li><p>Internal URLs you can't share</p> </li> <li><p>Secrets from environment variables</p> </li> <li><p>Sensitive logs</p> </li> </ul> <p>Keep the prompt focused on the performance issue. Give the agent enough context to help, but not more than it needs.</p> <h2 id="heading-conclusion">Conclusion</h2> <p>In this tutorial, you learned how to turn a performance audit finding into an AI fix prompt.</p> <p>You created:</p> <ul> <li><p>A structured <code>Finding</code> type</p> </li> <li><p>A way to rank findings</p> </li> <li><p>A <code>buildFixPrompt</code> function</p> </li> <li><p>A clipboard-first agent handoff</p> </li> <li><p>A DevTools panel button</p> </li> <li><p>A verification loop for checking the result</p> </li> </ul> <p>The main idea is simple: performance tools produce evidence, and coding agents need context. A good AI patch brief connects the two.</p> <p>PerfLens is one example of this workflow. If you want to try the extension or inspect how it implements this flow, you can find it here:</p> <ul> <li><p>Chrome Web Store: <a href="https://chromewebstore.google.com/detail/perflens/gkogamlpcnneeficmcdcnnnhobnbebdc">PerfLens</a></p> </li> <li><p>Source code: <a href="http://github.com/oluwatosinolamilekan/PerfLens">GitHub</a></p> </li> </ul>

How to apply

  1. 1 Read the full details above and confirm you meet the eligibility criteria.
  2. 2 Prepare your documents — an updated CV, and any cover letter, proposal or certificates required.
  3. 3 Click Apply on official site to complete your application on Olamilekan Lamidi’s official page.
  4. 4 Submit as early as possible — many close once filled.
Apply on official site

Sourced from freecodecamp. Always verify details on the official website. Opportunihub never charges you to apply.

Frequently asked questions

How do I apply for How to Turn Performance Audits into AI Fix Prompts with a DevTools Extension?

Review the full details and eligibility on this page, prepare your documents, then use the “Apply on official site” button to complete your application on Olamilekan Lamidi’s official page.

Is this opportunity remote or location-based?

This opportunity is remote-friendly and open to applicants who can work from anywhere.

Is How to Turn Performance Audits into AI Fix Prompts with a DevTools Extension free to apply for?

Opportunihub lists this Course for free. Legitimate Courses do not ask for payment to apply — never pay a fee to submit an application.