A rack of letters is only half of a word search — the other half is shape. This free Word Finder starts from your letters, then narrows by exact length, opening letters, closing letters, or a string the word must contain, and returns every match grouped by length with Scrabble scores. It is the tool for when you know more than your tiles: a slot size, a hook letter, or a fragment already sitting on the board.
How the Word Finder works
First the rack test: a word qualifies only if your letters can build it, each letter used at most as many times as you hold it, with ? as a blank tile that scores 0 for the letter it covers. Then your filters apply. Length is exact — set 7 and only seven-letter words survive. Starts with and ends with pin the word’s edges, and contains requires a letter string anywhere in the word, so ring finds ringlet and altering alike, as long as your letters can pay for them. Survivors are scored with Scrabble values and sorted the way players actually read: longest first, highest score first within each length.
A worked example
Give the finder the letters garden plus a blank, set the length to exactly 7, and it returns 32 words. The top of the group is a lesson in anagrams: angered, dangers, dragnet and derange all score 8, and any of them spends the whole rack. Now clear the length and try the letters triangle with contains set to ring: ten words survive, headed by altering at 9, with ringlet and tearing at 8. Same finder, two different questions — one about spending a rack in a slot of fixed size, one about building through a fragment.
Finder or unscrambler — which do you need?
The Word Unscrambler answers the purest question: what can these tiles make? Reach for the Word Finder the moment your question gains a condition. Playing onto a word already on the board? Put its opening letters in starts with. Setting up a suffix play like -ing or -ed? That is ends with. Filling a fixed gap between two played words? Length plus contains will usually leave you a handful of candidates. Each filter you add trades breadth for precision, and the counts at the top of each group tell you exactly how much precision you have bought.
Practical finding tips
Use contains for board strings rather than single letters — a two- or three-letter string is dramatically more selective. When a search returns nothing, remove the contains filter first; it is the usual culprit, because the string’s letters must come out of your rack too. Spend blanks reluctantly: run the search once without the ? to see what your real tiles earn, and only then ask what the blank adds. And read the second group, not just the first — a shorter word that lands on a premium square routinely out-scores the longest word played plain.
Limitations worth knowing
Scores are Scrabble values only; for Words With Friends or Word Chums pricing, the Word Solver applies those tables instead. The filters are literal — contains finds the string anywhere, including places you did not intend — and every letter of a matching word, filters included, must be covered by your rack. Our list is broader than any single game’s dictionary, so a rare entry may appear that a particular game would reject. Results are capped at the best 1,000 for display; the true total is always stated, and one more filter will bring the rest into view.
Word Finder – frequently asked questions
Is the Word Finder free?
Yes — unlimited searches, no sign-up, and it runs in your browser against our 359,039-word list.
How is this different from the Word Unscrambler?
The unscrambler solves a rack and nothing else. The finder adds four filters — exact length, starts with, ends with and contains — for searches where the board or the slot imposes conditions on top of your tiles.
Why is a word I expected missing?
Almost always because its letters cannot be covered by your rack once the filters’ letters are paid for too — a contains string is not free. Check also that the length filter is not set to a different size than you intended.
Can I search with a blank tile?
Yes — type ? in the letters box. It stands for any letter, and words that need it show that letter scoring 0, as on a real board.
More word tools and lists
Browse the full collection on our Word Finder & Word Tools hub. Closest companions: the Word Unscrambler, the Words With Letters finder for include/exclude rules across whole words, and the Random Word Generator when you want words with no rack at all.
Embed this tool on your website — free
Copy the code below to add this working tool to your own page. A small credit link stays with it — that’s all we ask.
function ilmScoreWord(w, VAL) {
var s = 0;
for (var i = 0; i < w.length; i++) s += VAL[w[i]] || 0;
return s;
}
function ilmRackCounts(rack) {
var counts = {}, wild = 0;
rack = (rack || ”).toLowerCase();
for (var i = 0; i < rack.length; i++) {
var ch = rack[i];
if (ch === ‘?’ || ch === ‘*’) wild++;
else if (ch >= ‘a’ && ch <= ‘z’) counts[ch] = (counts[ch] || 0) + 1;
}
return { counts: counts, wild: wild };
}
// Rack solver: every word buildable from the rack (subset of tiles, ? = blank,
// blank-covered letters score 0), scored with VAL. opts may carry starts,
// ends, contains (lowercase strings) and exactLen (0 = any).
// Returns [{w, s}] sorted length desc, score desc, A-Z.
function ilmRackSolve(rack, words, VAL, opts) {
opts = opts || {};
var rc = ilmRackCounts(rack), counts = rc.counts, wild = rc.wild;
var total = wild;
for (var k0 in counts) total += counts[k0];
var starts = (opts.starts || ”).toLowerCase();
var ends = (opts.ends || ”).toLowerCase();
var contains = (opts.contains || ”).toLowerCase();
var exactLen = opts.exactLen || 0;
var out = [];
for (var j = 0; j < words.length; j++) {
var w = words[j];
if (w.length < 2 || w.length > total) continue;
if (exactLen && w.length !== exactLen) continue;
if (starts && w.indexOf(starts) !== 0) continue;
if (ends && w.slice(w.length – ends.length) !== ends) continue;
if (contains && w.indexOf(contains) === -1) continue;
var need = {};
for (var k = 0; k < w.length; k++) { var c = w[k]; need[c] = (need[c] || 0) + 1; }
var ok = true, deficit = 0, score = 0;
for (var L in need) {
var have = counts[L] || 0;
if (need[L] <= have) score += VAL[L] * need[L];
else {
deficit += need[L] – have;
score += VAL[L] * have;
if (deficit > wild) { ok = false; break; }
}
}
if (ok) out.push({ w: w, s: score });
}
out.sort(function (a, b) {
return b.w.length – a.w.length || b.s – a.s || (a.w < b.w ? -1 : a.w > b.w ? 1 : 0);
});
return out;
}
// Crossword pattern solver: pattern is letters plus ? or . for unknown
// squares. If len is given and longer than the pattern, the pattern is
// padded with ? on the right; if the pattern is longer than len, no match.
// Returns matching words sorted A-Z.
function ilmCrossword(pattern, words, len) {
pattern = (pattern || ”).toLowerCase().replace(/\./g, ‘?’);
var effLen = len || pattern.length;
if (pattern.length > effLen) return [];
var pat = pattern;
while (pat.length < effLen) pat += ‘?’;
var out = [];
for (var j = 0; j < words.length; j++) {
var w = words[j];
if (w.length !== effLen) continue;
var ok = true;
for (var i = 0; i < effLen; i++) {
var p = pat[i];
if (p !== ‘?’ && p !== w[i]) { ok = false; break; }
}
if (ok) out.push(w);
}
out.sort();
return out;
}
// Pattern + rack solver (Word Solver): the word must match the pattern
// positionally; letters on fixed squares are already on the board (free),
// letters on ? squares must come from the rack (? in the rack = blank tile,
// blank-covered letters score 0). Returns [{w, s}] score desc, A-Z.
function ilmPatternRackSolve(rack, pattern, words, VAL) {
pattern = (pattern || ”).toLowerCase().replace(/\./g, ‘?’);
var rc = ilmRackCounts(rack), counts = rc.counts, wild = rc.wild;
var out = [];
for (var j = 0; j < words.length; j++) {
var w = words[j];
if (w.length !== pattern.length) continue;
var ok = true, score = 0;
var needFromRack = {};
for (var i = 0; i < w.length; i++) {
var p = pattern[i];
if (p >= ‘a’ && p <= ‘z’) {
if (p !== w[i]) { ok = false; break; }
score += VAL[w[i]];
} else {
needFromRack[w[i]] = (needFromRack[w[i]] || 0) + 1;
}
}
if (!ok) continue;
var deficit = 0;
for (var L in needFromRack) {
var have = counts[L] || 0;
if (needFromRack[L] <= have) score += VAL[L] * needFromRack[L];
else {
deficit += needFromRack[L] – have;
score += VAL[L] * have;
if (deficit > wild) { ok = false; break; }
}
}
if (ok) out.push({ w: w, s: score });
}
out.sort(function (a, b) {
return b.s – a.s || (a.w < b.w ? -1 : a.w > b.w ? 1 : 0);
});
return out;
}
// Letter filter (Words With Letters): include = letters that must ALL be in
// the word (multiset: "ee" means at least two e’s); exclude = letters that
// must NOT appear. Optional exactLen, starts, ends. Returns words A-Z.
function ilmFilterWords(words, f) {
f = f || {};
var inc = (f.include || ”).toLowerCase();
var exc = (f.exclude || ”).toLowerCase();
var starts = (f.starts || ”).toLowerCase();
var ends = (f.ends || ”).toLowerCase();
var exactLen = f.exactLen || 0;
var incNeed = {};
for (var i = 0; i < inc.length; i++) {
var c0 = inc[i];
if (c0 >= ‘a’ && c0 <= ‘z’) incNeed[c0] = (incNeed[c0] || 0) + 1;
}
var excSet = {};
for (var e = 0; e < exc.length; e++) {
var c1 = exc[e];
if (c1 >= ‘a’ && c1 <= ‘z’) excSet[c1] = true;
}
var out = [];
for (var j = 0; j < words.length; j++) {
var w = words[j];
if (exactLen && w.length !== exactLen) continue;
if (starts && w.indexOf(starts) !== 0) continue;
if (ends && w.slice(w.length – ends.length) !== ends) continue;
var ok = true;
for (var x = 0; x < w.length; x++) if (excSet[w[x]]) { ok = false; break; }
if (!ok) continue;
var wc = {};
for (var y = 0; y < w.length; y++) wc[w[y]] = (wc[w[y]] || 0) + 1;
for (var L in incNeed) if ((wc[L] || 0) < incNeed[L]) { ok = false; break; }
if (ok) out.push(w);
}
out.sort();
return out;
}
// Random picker: opts {count, len (0 = any 2-15), startsWith}. rng() must
// return [0,1). Samples without replacement.
function ilmRandomWords(words, opts, rng) {
opts = opts || {};
var len = opts.len || 0;
var sw = (opts.startsWith || ”).toLowerCase();
var pool = [];
for (var j = 0; j < words.length; j++) {
var w = words[j];
if (len && w.length !== len) continue;
if (sw && w.indexOf(sw) !== 0) continue;
pool.push(w);
}
var count = Math.min(opts.count || 5, pool.length);
var picked = [];
for (var n = 0; n < count; n++) {
var idx = Math.floor(rng() * pool.length);
picked.push(pool[idx]);
pool.splice(idx, 1);
}
return picked;
}
// Scramble: Fisher-Yates shuffle of the word’s letters, retried until the
// result differs from the original (words made of one repeated letter are
// returned unchanged — none are in the game list).
function ilmScrambleWord(word, rng) {
var letters = word.split(”);
var distinct = {};
for (var d = 0; d < letters.length; d++) distinct[letters[d]] = true;
var nDistinct = 0;
for (var k in distinct) nDistinct++;
if (nDistinct < 2) return word;
for (var attempt = 0; attempt < 200; attempt++) {
var a = letters.slice();
for (var i = a.length – 1; i > 0; i–) {
var j = Math.floor(rng() * (i + 1));
var tmp = a[i]; a[i] = a[j]; a[j] = tmp;
}
var s = a.join(”);
if (s !== word) return s;
}
return letters.slice().reverse().join(”);
}
// ~150 common English words for the Word Scramble game (4-8 letters).
var ILM_GAME_WORDS = [‘apple’,’banana’,’orange’,’garden’,’planet’,’silver’,’market’,’window’,’summer’,’winter’,’spring’,’autumn’,’bridge’,’castle’,’dragon’,’friend’,’school’,’pencil’,’paper’,’river’,’ocean’,’forest’,’jungle’,’desert’,’island’,’mountain’,’valley’,’village’,’kitchen’,’bedroom’,’picture’,’camera’,’guitar’,’piano’,’violin’,’trumpet’,’basket’,’bottle’,’candle’,’mirror’,’button’,’pocket’,’ticket’,’travel’,’journey’,’holiday’,’picnic’,’breakfast’,’dinner’,’supper’,’cheese’,’butter’,’coffee’,’sugar’,’pepper’,’lemon’,’melon’,’grape’,’peach’,’mango’,’rabbit’,’turtle’,’monkey’,’tiger’,’zebra’,’panda’,’koala’,’eagle’,’shark’,’whale’,’snake’,’horse’,’sheep’,’chicken’,’spider’,’flower’,’garden’,’hammer’,’ladder’,’rocket’,’planet’,’comet’,’meteor’,’galaxy’,’nebula’,’tunnel’,’harbor’,’anchor’,’sailor’,’pirate’,’treasure’,’diamond’,’golden’,’copper’,’iron’,’steel’,’wooden’,’cotton’,’leather’,’plastic’,’magnet’,’battery’,’engine’,’wheel’,’brake’,’helmet’,’jacket’,’gloves’,’scarf’,’boots’,’socks’,’shirt’,’dress’,’skirt’,’watch’,’clock’,’phone’,’tablet’,’laptop’,’screen’,’keyboard’,’mouse’,’printer’,’speaker’,’dancer’,’singer’,’farmer’,’doctor’,’nurse’,’teacher’,’writer’,’artist’,’baker’,’driver’,’hunter’,’fisher’,’sailor’,’soldier’,’captain’,’general’,’king’,’queen’,’prince’,’knight’,’wizard’,’witch’,’giant’,’fairy’,’elf’,’dwarf’,’goblin’,’troll’,’phoenix’,’unicorn’,’mermaid’,’thunder’,’lightning’,’rainbow’,’snowflake’,’raindrop’,’sunshine’,’moonlight’,’starlight’,’breeze’,’storm’,’cloud’,’fog’,’frost’,’ice’,’snow’,’rain’,’wind’,’wave’,’sand’,’stone’,’rock’,’cliff’,’cave’,’lake’,’pond’,’stream’,’waterfall’,’meadow’,’prairie’,’savanna’,’tundra’,’volcano’,’glacier’,’canyon’,’oasis’,’lagoon’,’coral’,’pearl’,’shell’,’feather’,’wing’,’claw’,’horn’,’tail’,’mane’];
ILM_GAME_WORDS = ILM_GAME_WORDS.filter(function (w, i) { return ILM_GAME_WORDS.indexOf(w) === i; });
if (typeof module !== ‘undefined’) {
module.exports = { ILM_SCRABBLE: ILM_SCRABBLE, ILM_WWF: ILM_WWF, ILM_CHUMS: ILM_CHUMS,
ilmScoreWord: ilmScoreWord, ilmRackSolve: ilmRackSolve, ilmCrossword: ilmCrossword,
ilmPatternRackSolve: ilmPatternRackSolve, ilmFilterWords: ilmFilterWords,
ilmRandomWords: ilmRandomWords, ilmScrambleWord: ilmScrambleWord, ILM_GAME_WORDS: ILM_GAME_WORDS };
}
var WORDLIST_URL = ‘https://ilmhunt.com/wp-content/uploads/2026/10/wordlist.txt’;
var WORDS = null, LOADING = false;
function sendH(){ try { parent.postMessage({wpcId: 5215, wpcH: document.body.scrollHeight + 16}, ‘*’); } catch (e) {} }
window.addEventListener(‘load’, sendH);
function st(msg){ document.getElementById(‘status’).textContent = msg; }
function ensureWords(cb){
if (WORDS) { cb(); return; }
if (LOADING) { return; }
LOADING = true; st(‘Loading the word list (359,039 words)…’);
fetch(WORDLIST_URL).then(function(r){ return r.text(); }).then(function(t){
WORDS = t.split(/\r?\n/).filter(function(x){ return x.length > 0; });
st(‘Word list ready — ‘ + WORDS.length.toLocaleString(‘en-US’) + ‘ words.’);
cb();
}).catch(function(){ LOADING = false; st(‘Could not load the word list. Check your connection and press Find Words again.’); });
}
function render(res){
var box = document.getElementById(‘results’);
if (!res.length) { box.innerHTML = ‘<p class="none">No words match all of that. Remove one filter — the contains box is the usual culprit.</p>’; sendH(); return; }
var cap = 1000, shown = res.slice(0, cap), html = ”, curLen = -1;
shown.forEach(function(x){
if (x.w.length !== curLen) {
if (curLen !== -1) html += ‘</div>’;
curLen = x.w.length;
var n = res.filter(function(y){ return y.w.length === curLen; }).length;
html += ‘<div class="grp"><h3>’ + curLen + ‘ letters — ‘ + n + ‘ word’ + (n === 1 ? ” : ‘s’) + ‘</h3>’;
}
html += ‘<span class="chip">’ + x.w + ‘<sup>’ + x.s + ‘</sup></span>’;
});
html += ‘</div>’;
if (res.length > cap) html += ‘<p class="none">Showing the best ‘ + cap.toLocaleString(‘en-US’) + ‘ — narrow with length or contains to see the rest.</p>’;
box.innerHTML = html;
st(res.length.toLocaleString(‘en-US’) + ‘ words found.’);
sendH();
}
function clean(id){ return document.getElementById(id).value.replace(/[^a-zA-Z]/g, ”).toLowerCase(); }
function run(){
ensureWords(function(){
var rack = document.getElementById(‘rack’).value.replace(/[^a-zA-Z?*]/g, ”).slice(0, 15);
if (rack.length < 2) { st(‘Enter at least 2 letters.’); return; }
render(ilmRackSolve(rack, WORDS, ILM_SCRABBLE, { starts: clean(‘starts’), ends: clean(‘ends’),
contains: clean(‘contains’), exactLen: parseInt(document.getElementById(‘len’).value, 10) }));
});
}
document.getElementById(‘go’).addEventListener(‘click’, run);
document.getElementById(‘rack’).addEventListener(‘keydown’, function(e){ if (e.key === ‘Enter’) run(); });
</script>
</body>
</html>
" style="width:100%;height:620px;border:0;display:block;overflow:hidden;" scrolling="no"></iframe></div>
<p><a href="https://ilmhunt.com/word-finder/" target="_blank" rel="noopener">Word Finder — Find Words by Letters, Length and Letter Strings</a> by <a href="https://ilmhunt.com/" target="_blank" rel="noopener">IlmHunt</a> — free online tools</p>
