Spot AI Writing Tells in Your Own Text
Build a browser tool that highlights AI writing patterns in pasted text.
Introduction
30 Second Summary
You've probably read something online and felt a nagging suspicion that no human wrote it. The giveaway is usually a handful of phrases that keep showing up in machine writing.
In this project, you will build a web page that reads any block of text and lights up the phrases that give machine writing away. Everything runs in your browser, so there is no server, no API key and no bill.
What You'll Build
You paste three paragraphs into your own page, watch the cliches glow as you type, and send the live link to a friend who pastes in their own draft.
By the end of this project, you'll have:
- A page where you type into a text box and watch matched phrases light up instantly, each one carrying a badge that names the pattern it tripped.
- A live counter you can watch drop as you rewrite a sentence to sound more like yourself.
- A toggle that strips out every unmatched sentence, so a long document collapses to just its tells.
- A live URL on a free static host that you open on your phone to prove the whole thing is one self-contained file.
- Secret Mission: Extend your pattern list so you can add a new tell without touching the highlighting code.
Are there any prerequisites?
You need a text editor and a browser. Some basic HTML helps, but every line is given to you as you go.
Before We Start
You have probably read something online and felt certain an LLM wrote it. The words were fine, but something about the rhythm gave it away.
By the end of this project you will have your own page that catches those tells and names them. Before you build it, you need a target to build toward.
In this step, get ready to:
- Open the reference highlighter in your browser.
- Paste three paragraphs of AI-written text into it.
- Note which patterns it flags so you have a starter list for your own page.
Open the reference highlighter
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type the name of your browser, for example Chrome, and press Enter to open it.
- Type tools.simonwillison.net/llm-cliche-highlighter into the address bar and press Enter.
You should see a heading that reads LLM cliché highlighter, a large empty text box, and a row of buttons underneath it.
Why start with someone else's tool?
This page already solves the problem you are about to solve. Reading its output hands you a working target instead of a blank file.
The value you take away is the pattern list. Every phrase it colours in is a candidate for the list your own page will match against.
Paste in three paragraphs of AI-written text
- Copy the three paragraphs below, which are packed with the phrases people associate with machine writing:
In today's fast-paced digital landscape, artificial intelligence has become a game-changer for content creators everywhere. It's important to note that the technology continues to evolve at an unprecedented pace.
Furthermore, the implications of this shift cannot be overstated. Moreover, businesses that fail to adapt may find themselves left behind in an increasingly competitive market.
In conclusion, whether you're a seasoned professional or just starting out, now is the time to dive into the world of AI. The future belongs to those who embrace change.
What is in this sample?
- In today's fast-paced digital landscape is a stock opener that carries no information about the topic.
- game-changer and dive into are hype phrases that survive from first draft to final draft.
- Furthermore and Moreover are transition words that pile up far more often in machine writing than in human writing.
Before you paste it in, pick the one phrase you think the highlighter will flag first.
- Click into the large text box on the highlighter page.
- Paste the three paragraphs in.
- Hover over one of the coloured phrases to see which cliché it matched.
Analysis runs as you type, so the highlights appear the moment the text lands. Phrases across all three paragraphs should now be coloured in, each one naming the pattern it hit.
Nothing highlighted?
- Check the text actually landed in the box. An empty box still shows its own prompt asking you to paste text.
- Click Load example to load the tool's own sample. If that lights up, your paste never reached the box.
Why is the highlighter not flagging anything in my text?
Note the tells worth copying
The phrases you write down here become the pattern list your own page matches against later.
- Record the first flagged phrase: your first flagged phrase.
- Record the second flagged phrase: your second flagged phrase.
- Record the third flagged phrase: your third flagged phrase.
One button on the page shows you the whole list at once. Before you click it, how much of your three paragraphs do you think will survive the filter?
- Click Show just the highlights to strip out everything that did not match a pattern.
The three paragraphs collapse down to the flagged phrases on their own. That short list is your target for the rest of this project.
You have a target and a starter list of tells. Next up, you build the page that catches them yourself.
Build the Live Text Input
You've watched the reference highlighter flag sentences inside your own AI-written paragraphs. Now it's your turn to build the page that does the flagging.
Before a page can highlight anything, it needs somewhere to put text and somewhere to show the result. In this step you'll build both panes and wire them together so the right one echoes whatever you type.
In this step, get ready to:
- Create an index.html file and open it straight from your file system.
- Build a two-pane layout with a text box on the left and a results pane on the right.
- Wire a script that mirrors your typing into the results pane in real time.
Create your project folder and page file
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir ai-tell-highlighter
cd ai-tell-highlighter
- Confirm you are inside the new folder by running:
pwd
The path printed back ends with ai-tell-highlighter.
- Create your empty page file by running the command for your system:
macOS
touch index.html
Windows
New-Item index.html
- Confirm the file exists by running:
ls
You should see index.html in the output.
Don't see index.html in the list?
- Check the pwd output again. If it does not end in ai-tell-highlighter, the file landed somewhere else.
- Windows users running the macOS command get an error, because touch is not a PowerShell command.
My file creation command ran but I cannot find the file
Build the two-pane layout
A highlighter needs two halves: somewhere to put the raw text, and somewhere to show what came back. You'll build both with plain HTML before adding any logic.
- Press Cmd+Space (macOS) or the Windows key (Windows) to open your search bar.
- Type the name of your text editor, for example VS Code, and press Enter.
- Click File in the top menu bar.
- Click Open Folder.
- Select the ai-tell-highlighter folder on your Desktop, then click Open.
Your index.html appears in the editor's file list, empty for now.
- Build the page skeleton by copying this into index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>AI Writing Tells</title>
</head>
<body>
<h1>Spot AI Writing Tells</h1>
<div class="panes">
<!-- Left pane: where you paste or type text -->
<textarea id="input" placeholder="Paste or type your text here"></textarea>
<!-- Right pane: where results show up -->
<div id="output"></div>
</div>
</body>
</html>
What does this code do?
- The textarea with the id input is the left pane you paste or type into.
- The empty div with the id output is the right pane, waiting for results.
- The panes class wraps both so you can lay them out side by side next.
- Save index.html.
- Open the ai-tell-highlighter folder in Finder (macOS) or File Explorer (Windows).
- Double-click index.html to open it in your browser.
You should see the heading Spot AI Writing Tells with an empty text box underneath it. The address bar starts with file://, so the page is running straight off your disk.
- Back in your editor, find the </head> line in index.html.
- Give the two panes their shape by copying this in just above that line:
<style>
/* Page-level typography and breathing room */
body { font-family: system-ui, sans-serif; padding: 24px; }
/* Sit the two panes side by side with a gap between them */
.panes { display: flex; gap: 16px; }
/* Equal width, equal height and a readable text size for both panes */
#input, #output {
flex: 1; min-height: 320px; padding: 12px;
border: 1px solid #ccc; font-size: 16px; line-height: 1.5;
}
</style>
How the panes end up side by side
This is plain CSS living inside the page, so there is no second file to load.
- The display: flex rule on .panes lines its two children up in a row.
- The flex: 1 rule gives each pane an equal share of the width.
- The min-height rule keeps the results pane visible while it is still empty.
- Save index.html.
- Switch back to your browser tab and refresh the page.
The text box and the empty results pane now sit side by side, each taking half the width with a thin grey border.
Panes still stacked on top of each other?
- Check the <style> block sits above </head>, not below it.
- Check the class in your CSS reads .panes and matches class="panes" in your markup.
- An unsaved file looks identical in the browser, so save before you refresh.
Why are my two panes not sitting side by side?
Mirror your typing into the results pane
Right now the right-hand pane is dead space. A few lines of JavaScript make it echo whatever sits in the text box.
- In your editor, find the </body> line in index.html.
- Wire the two panes together by copying this in just above that line:
<script>
// Grab both panes once so the code can reuse them
const input = document.getElementById("input");
const output = document.getElementById("output");
// Copy the raw text from the text box into the results pane
function render() {
output.textContent = input.value;
}
// Runs on every keystroke, paste and delete
input.addEventListener("input", render);
</script>
What does this code do?
- The two document.getElementById calls find each pane once, so the page is not searched again on every keystroke.
- The render function copies the current value of the text box into the results pane.
- The input event fires on typing, pasting and deleting, which is why there is no button to press.
Before you refresh, what do you think the right pane will do while you type? Make a guess, then test it.
- Save index.html.
- Switch back to your browser tab and refresh the page.
- Type It's important to note that this is a game-changer. into the text box on the left.
Every character lands in the results pane as you type. Delete a word and it disappears from the right side too.
Nothing appearing as you type?
- Check the <script> block sits above </body>, so both panes exist by the time it runs.
- Check the ids in your script match input and output exactly, because ids are case-sensitive.
- Save the file, then refresh. The browser keeps running the old version until you do both.
Why is my results pane not updating when I type?
✔️ Awesome, I've got everything!
Great. Double check you've saved index.html before you move on.
ⓧ I'd like to double check the full code
Scroll up and confirm all three pieces are in your file, in this order:
- The <style> block, sitting just above </head>.
- The page skeleton, with the textarea and the output pane inside the panes wrapper.
- The <script> block, sitting just above </body>.
Your page reads text and echoes it back live, with no server anywhere in the loop. Next up, you'll hand it a list of AI writing tells and watch the first cliche light up.
Highlight the First AI Writing Patterns
Your page already mirrors whatever you type, but it treats every sentence the same way. A tell only stands out once the page knows what a tell looks like.
In this step you hand the page a list of five phrases that give away machine writing. Then you wrap every match in a span so the page can colour it.
In this step, get ready to:
- Store five AI writing phrases in a pattern list.
- Wrap every matched phrase in a highlight span.
- Colour the highlights so tells jump off the page.
Add a list of AI writing patterns
Your page has no opinion about which phrases are suspicious. A plain list of strings is enough to give it one.
- In index.html, find the opening <script> tag.
- Add your pattern list as the first thing inside that script by pasting this code:
// Phrases that often give away machine writing
const patterns = [
"In conclusion",
"It's important to note",
"Furthermore",
"dive into",
"game-changer"
];
What does this code do?
- patterns holds the five phrases your page will hunt for.
- Each phrase is a plain string, so catching a new tell later costs you one more line.
- Save index.html.
- Refresh your browser tab.
- Open your browser console with Cmd+Option+J (macOS) or Ctrl+Shift+J (Windows).
- Confirm the list loaded by running this in the console:
patterns.length
The console prints 5, one for each phrase you just added.
Console can't find your pattern list?
- Save index.html before you refresh. An unsaved file still serves the old script.
- Check the list sits inside the <script> block and not below the closing tag.
Why can't my browser console see the pattern list I added to my HTML file?
Wrap every match in a highlight span
A list of phrases does nothing until something scans your text for them. One regular expression built from the list finds all five in a single pass.
- Build the matcher by pasting this code directly below your pattern list:
// Build one pattern that matches any phrase in the list
const patternRegex = new RegExp(patterns.join("|"), "gi");
// Wrap every match in a span the CSS can colour
function highlight(text) {
return text.replace(patternRegex, match => `<span class="highlight">${match}</span>`);
}
What does this code do?
- patterns.join("|") glues your phrases into one pattern, so a hit on any of them counts as a match.
- The g flag catches every match in the text, and the i flag ignores capital letters.
- highlight returns your text with each match wrapped in a span. It reads the raw text once and builds the marked up string in a single pass.
- Scroll down to the input listener in your <script> block.
- Find the line that copies your typed text into the results pane:
output.textContent = input.value;
- Swap that line for this one, so the pane renders your wrapped text:
output.innerHTML = highlight(input.value);
Why innerHTML instead of textContent?
textContent prints your span as literal characters on the page.
innerHTML tells the browser to read that span as HTML. That is what turns it into a real element you can colour.
- Save index.html.
- Refresh your browser tab.
- Type In conclusion, this matters. into the textarea.
- Right click the words In conclusion in the results pane, then choose Inspect.
In the Elements panel, In conclusion now sits inside a <span class="highlight">. Your page has caught its first tell.
No span in the Elements panel?
- Check the pattern list and the matcher both sit inside the same <script> block.
- Confirm you typed a phrase from your list, spelling included.
- Make sure the listener line now reads innerHTML and not textContent.
Why isn't my replace function wrapping the matched phrase in a span?
Colour the highlights
A span with no styling looks identical to plain text. One CSS rule turns every match into something you can spot from across the room.
- In index.html, find the closing </style> tag.
- Give your matches a colour by pasting this rule just above it:
/* Colour every phrase the matcher wrapped */
.highlight {
background: #ffe066;
color: #111;
border-radius: 3px;
padding: 0 2px;
}
What does this code do?
- background puts a warm block of colour behind every match.
- color keeps the text readable against that block.
- padding and border-radius round the edges so each hit reads as a badge.
- Save index.html.
- Refresh your browser tab.
Before you paste the text below, how many of your five patterns do you think it trips? Take a guess, then check.
- Paste this text into the textarea:
In conclusion, remote work is a game-changer. It's important to note that teams still need to dive into the details.
Four phrases light up in yellow: In conclusion, game-changer, It's important to note and dive into.
Delete one of those phrases from the textarea and its colour disappears as you type. Your page is now reading along with you.
Text staying plain?
- Check the rule sits inside the <style> block, above the closing </style> tag.
- Match the class name in your CSS to the class name in your span, letter for letter.
Why isn't my highlight CSS class showing any colour in the browser?
✔️ Awesome, I've got everything!
Great, double check you've saved index.html before you move on.
ⓧ I'd like to double check the full code
Scroll up and confirm all four pieces are in your file, in this order:
- The patterns list of five phrases, at the top of your <script> block.
- The patternRegex line and the highlight function, directly below the pattern list.
- The output.innerHTML = highlight(input.value); line inside your input listener.
- The .highlight rule, just above your closing </style> tag.
Your page now spots five tells and paints them yellow. Next up, you'll label each highlight with the pattern that caught it and watch a running count move as you edit.
Add Match Badges and a Live Counter
Your page already lights up the tells as you type. Right now every match wears the same colour, so five different problems all look like one.
A highlight that names its own pattern turns a vague warning into feedback you can act on. A running total turns your edits into a score that drops as you clean the text up.
In this step, get ready to:
- Attach a badge to every highlight naming the pattern that matched.
- Add a counter above the results pane that tallies every match.
- Watch the counter drop as you edit a tell out of your text.
Name the pattern behind every highlight
Your highlighter already knows which phrase tripped each match. It throws that information away the moment it wraps the text.
- In index.html, scroll to the <script> block at the bottom of the file.
- Check the name of the array holding your five phrases.
The code below calls that array patterns. Swap in your own name if you called it something else.
- Give your highlighter a memory for which pattern matched by pasting this function above your input event listener:
// Build the badged HTML and count the hits in one pass over the raw text
function markMatches(text) {
let html = '';
let count = 0;
let i = 0;
while (i < text.length) {
// Does one of your patterns start right here?
const hit = patterns.find(p => text.slice(i, i + p.length).toLowerCase() === p.toLowerCase());
if (hit) {
// Wrap the match, then tag it with the pattern that tripped
html += '<span class="highlight">' + text.slice(i, i + hit.length) + '<span class="badge">' + hit + '</span></span>';
count += 1;
i += hit.length;
} else {
html += text[i];
i += 1;
}
}
return { html, count };
}
What does this code do?
- patterns.find(...) checks whether any phrase in your list starts at the current position in the text.
- The loop walks the raw text once and builds the marked up string as it goes. That way it never re-matches the markup it just inserted.
- return { html, count } hands back both the marked up text and the running total, so one call can feed the pane and the counter.
- Save index.html.
- Switch back to your browser and refresh the page.
- Open the browser console with Cmd+Option+J (macOS) or Ctrl+Shift+J (Windows).
- Prove the function works by running this in the console:
markMatches('Furthermore, we dive into the data.').count
You should see 2 in the console. That is one hit for Furthermore and one for dive into.
Console throwing a ReferenceError?
- The name in the error is the name your code expected to find. If it points at your pattern list, rename patterns inside the function to match the array you already declared.
- Make sure the function sits inside the same <script> block as your pattern list, below the array.
- Why is my function not seeing my pattern list?
- Find the line inside your input event listener that writes the highlighted text into the results pane.
- Route that write through your new function by replacing the line with these two lines:
// Send the raw text through markMatches and paint the badged output
const marked = markMatches(document.getElementById("input").value);
document.getElementById("results").innerHTML = marked.html;
What changed here?
- markMatches now does the matching, so the listener only decides where the output lands.
- marked holds both halves of the result. The pane takes the markup and the counter takes the total.
- This code reads your textarea as input and your pane as results. Swap those ids for the ones in your own markup if they differ.
- Save index.html and refresh your browser.
- Type this sentence into the textarea:
Furthermore, we dive into the data.
Each coloured phrase now carries the pattern name right after it, in plain unstyled text.
- Scroll up to the <style> block in the <head> of your file.
- Turn those bare names into small pills by adding this rule at the end of your CSS:
.badge {
margin-left: 4px;
padding: 1px 6px;
border-radius: 8px;
background: #1f2937;
color: #ffffff;
font-size: 11px;
vertical-align: middle;
}
What does this CSS do?
- padding and border-radius turn the pattern name into a rounded pill instead of loose text.
- font-size of 11px keeps the badge quieter than the sentence it labels.
- vertical-align: middle lines the pill up with the text it sits beside, so your paragraph still reads cleanly.
- Save index.html and refresh your browser.
The pattern name now sits in a small dark pill tucked against the end of each highlight.
Badge still looks like plain text?
- Check that the class in your rule is .badge and the span your function builds uses class="badge". Class names are case-sensitive.
- Make sure the rule landed inside the <style> block. CSS pasted into the body is ignored.
- Why is my badge CSS not applying?
Count every match above the pane
Badges tell you what went wrong in each sentence. A total tells you how much is left across the whole draft.
- Find the results pane element in your HTML.
- Give the total a home on the page by adding this line directly above the pane:
<div id="count">0 matches</div>
Why the counter sits above the pane
The pane grows as long as your text, so a counter underneath would scroll out of sight on a real draft. Above the pane it stays in view while you edit.
- Save index.html and refresh your browser.
You should see 0 matches sitting just above your results pane.
- Return to the input event listener in your <script> block.
- Make the total move with the text by adding this line directly below the line that sets the results pane:
// Show how many patterns tripped in the text you are editing
document.getElementById("count").textContent = marked.count + " matches";
- Save index.html and refresh your browser.
- Type this sentence into the textarea:
Furthermore, we dive into the data.
The counter reads 2 matches while the badges name each one.
Counter frozen on 0 matches?
- Check the new line sits inside the input event listener, below const marked. Outside the listener it only runs once, on page load.
- Confirm the id in your markup is count and matches the id in the code exactly.
- Why does my counter never update as I type?
Watch the counter fall as you edit
The counter earns its place when it moves in the wrong direction on a bad draft. Here is a paragraph stuffed with the tells on your list.
Before you paste it in, how many of your five patterns do you think this paragraph trips?
In conclusion, it's important to note that this tool is a game-changer. Furthermore, let's dive into the results.
- Clear the textarea.
- Paste the paragraph into the textarea.
The counter reads 5 matches, and every badge names a different pattern from your list.
- Delete the word Furthermore and the comma after it.
The counter drops to 4 matches the instant the phrase disappears. That live drop is the feedback loop you will run your own drafts through.
✔️ Awesome, I've got everything!
Great, double check you have saved index.html.
ⓧ I'd like to double check the full code
Your file should now contain these four additions on top of what you built in the last step:
- The markMatches function sitting above your input event listener.
- The two lines inside the listener that call markMatches and set the results pane.
- The .badge rule at the end of your <style> block.
- The <div id="count">0 matches</div> element above your results pane, plus the line in the listener that fills it.
Scroll back up through this step and confirm each one is present, in order.
Your page now names every tell and keeps score while you type. Next up, you'll strip out every sentence that has nothing wrong with it and put the file on a live URL.
Publish Your Highlighter
Your highlighter now names every tell it finds and keeps a running count. On a long document though, those flagged sentences sit buried in paragraphs of perfectly clean writing.
A matches-only toggle collapses the pane down to just the sentences that tripped a pattern. Then you'll put the file on the open web, so it works from any device you pick up.
In this step, get ready to:
- Add a toggle that hides every sentence with no pattern match.
- Publish index.html to a free static host.
- Open your live URL on your phone.
Add the matches-only toggle
- Switch back to index.html in your editor.
- Give yourself a control to flip by pasting this markup directly above your results pane:
<label>
<input type="checkbox" id="matches-only">
Show only flagged sentences
</label>
What does this markup do?
- The <label> wraps the text around the checkbox, so clicking the words ticks the box too.
- The matches-only id is the handle your JavaScript uses to read whether the box is ticked.
- Save index.html.
- Refresh your browser tab.
A checkbox labelled Show only flagged sentences now sits above the results pane. Ticking it does nothing yet.
Don't see the checkbox?
- Check the markup landed inside your <body> and not inside a <script> tag.
- Unsaved edits never reach the browser, so confirm the file has no unsaved marker on its tab.
- Why is my checkbox not showing up on the page?
Filter the pane down to flagged sentences
The toggle needs two things. Something that strips out clean sentences, and a reason for the pane to redraw when the box flips.
- Teach the page about the toggle by pasting this block above your render function:
// Grab the toggle so the renderer can read whether it is ticked
const matchesOnly = document.getElementById("matches-only");
// Redraw the pane the moment the toggle flips
matchesOnly.addEventListener("change", render);
// Keep only the sentences where at least one pattern fires
function onlyFlagged(text) {
// Split on sentence endings and keep the punctuation attached
const sentences = text.split(/(?<=[.!?])\s+/);
// search() ignores a pattern's global flag, so matching cannot go stale between calls
const flagged = sentences.filter(sentence =>
patterns.some(pattern => sentence.search(pattern.regex) !== -1)
);
return flagged.join(" ");
}
What does this code do?
- matchesOnly holds the checkbox, and its change listener reruns the same renderer your typing already triggers.
- The split uses a lookbehind, so a full stop stays glued to the sentence it ends.
- onlyFlagged reuses the same five-item patterns list your highlighter already runs on, so the toggle can never disagree with the badges.
- Scroll down to your render function.
- Find the line that reads the textarea:
const text = input.value;
- Let the toggle decide which text gets highlighted, so the line now looks like this:
const text = matchesOnly.checked ? onlyFlagged(input.value) : input.value;
Before you try it, what do you expect the counter above the pane to do when you tick the box? Take a guess, then test it.
- Save index.html and refresh your browser.
- Paste in a few paragraphs where only one or two sentences carry a tell.
- Tick the checkbox.
The pane collapses to just the flagged sentences, badges still attached. The counter holds steady, because you hid clean sentences rather than removing any matches.
Pane goes blank when you tick the box?
- A blank pane usually means no sentence matched. Try text that contains one of your five phrases word for word.
- If the console reports that patterns is not defined, your new block landed above the pattern list instead of below it.
- Why does my filtered results pane come back empty?
✔️ Awesome, I've got everything!
Great. Double check you've saved index.html before you publish it.
ⓧ I'd like to double check the full code
Your file is well past a screenful now, so scroll up and confirm each piece from this step is present, in this order:
- The <label> holding the matches-only checkbox, directly above your results pane.
- The matchesOnly constant and its change listener.
- The onlyFlagged function, sitting above render.
- The rewritten const text line inside render.
Publish index.html and open it on your phone
Your page calls no API and loads no library, so any host that serves files can run it. You'll use Netlify, which publishes a dragged folder on its free plan.
Why you sign in before dropping
Netlify Drop protects an anonymous drop with a temporary password until someone claims it.
Signing in first means your URL is public the moment it goes live. That is exactly what the phone test needs.
- In a new browser tab, go to https://app.netlify.com/signup.
- Create your free account using whichever sign-up option you prefer.
- Go to https://app.netlify.com/drop.
- Drag the folder that holds index.html onto the drop zone in the middle of the page.
Netlify uploads the folder and publishes it in seconds. Your page goes live at a URL ending in netlify.app.
- Record your live URL: your live netlify.app URL
Before you open that URL on your phone, do you think the highlighter will work there? Your page never called a server, so what does it actually need from the network?
- Open the browser on your phone.
- Type your live URL into the address bar: your live netlify.app URL
- Type a sentence carrying one of your five patterns into the text box.
- Tick the matches-only checkbox.
The phrase highlights, the badge names the pattern, and the counter reads 1. The whole thing runs on a device that has never seen your project folder.
Live page asking for a password?
- A password prompt means the drop is still unclaimed. Sign in on your computer and claim the project, then reload the URL on your phone.
- A page listing your files instead of the highlighter means index.html was not at the top level of the folder you dragged.
- Why is my dropped Netlify site asking for a password?
Secret mission
Rank Your Worst Writing Habits
Your page tells you how many tells it found. It does not tell you which one you lean on most. Add a breakdown panel that counts every pattern separately and ranks them, so a paragraph of your writing turns into a leaderboard of your own habits.
Clean Up Your Resources
Clean Up Your Resources
Decide whether to keep your resources running, pause them to come back later, or delete them entirely. Your highlighter runs entirely in the browser and your static host is free, so nothing here is charging you anything.
Resources you used:
- index.html on your computer, holding the two-pane layout, pattern list, badges, counter and toggle.
- The deployed copy of index.html on your free static host, reachable at your live URL.
Keep everything running
No action needed. Choose this if you're still catching new writing tells and want the page one click away.
- Leave index.html where it is on your computer.
- Leave your live URL published so you can open the highlighter from any device.
What stays behind
Your static host account stays active whichever option you pick here. Closing an account is a separate decision, and your published page costs nothing while it sits there.
Pause - I'll come back to this later
Nothing runs in the background here, so pausing means taking the public page down and keeping the file. Choose this if you want the code without a live URL.
- Sign in to the static host you published to.
- Open the project page for the site you deployed.
- Use that project's delete option to take the site down.
- Reload your live URL in your browser.
You should see a not found page instead of your highlighter.
- Keep index.html on your computer so you can open it straight from your file system whenever you want it back.
Delete - I don't want to use this again
Remove all project resources and start fresh. Choose this if you don't plan to come back to the highlighter.
- Sign in to the static host you published to.
- Open the project page for the site you deployed.
- Use that project's delete option to remove the site.
- Reload your live URL in your browser.
You should see a not found page instead of your highlighter. That confirms the deployment is gone.
- Delete your local copy on macOS or Linux by running this command:
rm [[INDEX_PATH="path to your index.html file"]]
- Delete your local copy on Windows by running this command in PowerShell:
del [[INDEX_PATH="path to your index.html file"]]
Command says the file doesn't exist?
The path you gave the command has to point at the exact folder holding index.html. Drag the file into your terminal window to paste its full path.
Still stuck deleting it? Help me remove my file.
Nice Work!
Nice Work
Nice work. You've built a working AI writing tell detector that runs entirely in the browser, and you've published it to a live URL that anyone can open.
You've learned how to:
- Build a live text analyser in a single index.html file, with a textarea feeding a results pane that updates as you type.
- Match text against a pattern list and wrap every hit in a highlight span carrying a badge that names the pattern it tripped.
- Add a live counter and a toggle that collapses the pane down to only the flagged sentences, then deploy the page to a free static host and open it on your phone.
- Take on the Secret Mission to push your page further with an optional extension.
Ready to quiz yourself?