Unser Keyword Match Type Generator hilft dir, Google Ads Keywords automatisch in alle wichtigen Match Types (Exact, Phrase, Broad, Modified Broad) zu konvertieren. Statt jeden Begriff manuell anzupassen, kannst du hier deine Keyword-Liste einfügen und in Sekunden die fertigen Varianten generieren. Das spart Zeit, reduziert Fehler und macht deine Kampagnenplanung deutlich effizienter.
Alle Berechnungen laufen direkt im Browser, deine Daten werden nicht an einen Server gesendet. Damit bleibt deine Arbeit sicher und vertraulich.
Ob Einsteiger oder erfahrener SEA-Profi: Mit unserem Script erhältst du sofort ein klares, strukturiertes Ergebnis, das du direkt in Google Ads übernehmen kannst.
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1" />
<title>Keyword Match Type Generator – Dreamcodes</title>
<meta name="description" content="Dreamcodes, Keyword Match Type Generator: Erzeuge Exact, Phrase, Broad Modifier und Broad Keywords schnell. Duplikate entfernen, exportieren, per AJAX hochladen.">
<style>
:root{
--bg:#f7fafc;
--card:#ffffff;
--accent:#0b6fb2;
--muted:#6b7280;
--success:#0f9d58;
}
*{box-sizing:border-box}
body{
margin:0;
font-family:system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial;
background:var(--bg);
color:#0f172a;
-webkit-font-smoothing:antialiased;
}
header{
background:linear-gradient(90deg,#0b6fb2,#0d8bd6);
color:white;
padding:22px 18px;
}
header h1{ margin:0; font-size:20px; }
header p{ margin:6px 0 0; opacity:0.95; font-size:13px; }
.container{ max-width:1100px; margin:22px auto; padding:0 18px; }
.grid{
display:grid;
grid-template-columns:1fr 420px;
gap:18px;
}
@media (max-width:980px){
.grid{ grid-template-columns:1fr; }
}
.card{
background:var(--card);
border-radius:12px;
padding:16px;
box-shadow:0 6px 18px rgba(16,24,40,0.04);
}
.dropzone{
border:2px dashed rgba(11,111,178,0.12);
border-radius:10px;
padding:14px;
background:linear-gradient(180deg, rgba(255,255,255,0.9), rgba(255,255,255,0.8));
display:flex;
gap:12px;
align-items:center;
}
.dropzone.dragover{ border-color:rgba(11,111,178,0.4); background:#f0fbff; }
textarea{ width:100%; min-height:220px; resize:vertical; border:1px solid #eef2f7; padding:12px; border-radius:8px; font-family:inherit; font-size:14px; color:#0f172a; }
label{ font-weight:600; color:var(--muted); font-size:13px; }
.controls{ display:flex; gap:8px; margin-top:10px; flex-wrap:wrap; }
.btn{
background:var(--accent); color:white; border:none; padding:10px 12px; border-radius:8px; cursor:pointer; font-weight:700;
}
.btn.secondary{ background:#fff; color:var(--accent); border:1px solid rgba(11,111,178,0.12); }
.btn.ghost{ background:transparent; color:var(--accent); border:1px dashed rgba(11,111,178,0.12); }
.option-row{ display:flex; gap:12px; align-items:center; margin-top:12px; flex-wrap:wrap; }
.option-row .col{ display:flex; gap:8px; align-items:center; }
.result-list{ max-height:520px; overflow:auto; padding-top:8px; display:flex; flex-direction:column; gap:8px; }
.result-item{ background:#fbfdff; border-radius:8px; padding:8px; border:1px solid #eef6ff; display:flex; justify-content:space-between; gap:8px; align-items:center; font-size:14px; }
.muted{ color:var(--muted); font-size:13px; }
.stats{ display:flex; gap:12px; flex-wrap:wrap; margin-top:8px; }
.badge{ background:#eef6fb; color:var(--accent); padding:6px 8px; border-radius:999px; font-weight:700; font-size:13px; }
.footer{
margin-top:18px; display:flex; justify-content:space-between; align-items:center; flex-wrap:wrap;
}
footer.site{
margin-top:28px; text-align:center; color:var(--muted); font-size:13px;
}
footer.site a{ color:var(--accent); text-decoration:none; font-weight:700; }
.input-inline{ display:flex; gap:8px; align-items:center; }
input[type=text], input[type=url] { padding:8px 10px; border-radius:8px; border:1px solid #eef2f7; }
.small{ font-size:13px; color:var(--muted); }
.hint{ font-size:13px; color:var(--muted); margin-top:8px; }
.export-row{ display:flex; gap:8px; margin-top:12px; flex-wrap:wrap; }
.danger{ background:#ef4444; color:white; padding:8px 12px; border-radius:8px; border:none; cursor:pointer; }
.checkbox{ display:inline-flex; gap:6px; align-items:center; cursor:pointer; user-select:none; }
.input-number{ width:84px; padding:8px; border-radius:8px; border:1px solid #eef2f7; }
</style>
</head>
<body>
<header>
<div style="display:flex;flex-direction:column;gap:6px;max-width:1100px;margin:0 auto;">
<h1>Keyword Match Type Generator</h1>
<p>Erzeuge in Sekundenschnelle Exact, Phrase, Broad Modifier und Broad Varianten aus deiner Keyword Liste. Exportieren, kopieren oder optional per AJAX hochladen.</p>
</div>
</header>
<div class="container">
<div class="grid">
<div class="card">
<div class="dropzone" id="dropzone">
<div style="flex:1">
<label for="inputKeywords">Keywords einfügen oder Datei ziehen</label>
<textarea id="inputKeywords" placeholder="Gib Keywords ein eine Zeile gleich ein Keyword. Du kannst mehrere Wörter pro Zeile haben."></textarea>
<div class="hint">Beispiel: <span class="muted">schuhe kaufen</span></div>
</div>
<div style="width:140px;display:flex;flex-direction:column;gap:8px;align-items:flex-end">
<input id="fileInput" type="file" accept=".txt,.csv" style="display:none" />
<button class="btn" id="btnChoose">Datei wählen</button>
<button class="btn secondary" id="btnClear">Felder leeren</button>
</div>
</div>
<div class="card" style="margin-top:14px;padding:12px;">
<label>Match Types</label>
<div class="option-row">
<div class="col">
<input type="checkbox" id="optExact" checked /> <label for="optExact" class="small">Exact [keyword]</label>
</div>
<div class="col">
<input type="checkbox" id="optPhrase" checked /> <label for="optPhrase" class="small">Phrase "keyword"</label>
</div>
<div class="col">
<input type="checkbox" id="optBroadMod" checked /> <label for="optBroadMod" class="small">Broad Modifier +keyword</label>
</div>
<div class="col">
<input type="checkbox" id="optBroad" /> <label for="optBroad" class="small">Broad keyword</label>
</div>
</div>
<div class="option-row" style="margin-top:12px;">
<div class="col">
<label class="checkbox"><input type="checkbox" id="optRemoveDups" checked /> Duplikate entfernen</label>
</div>
<div class="col">
<label class="checkbox"><input type="checkbox" id="optLowercase" /> Alle Keywords klein</label>
</div>
<div class="col">
<label class="small">Broad Modifier mind Wörter</label>
<input id="bmMinWords" class="input-number" type="number" value="2" min="1" />
</div>
</div>
<div style="margin-top:12px;">
<label class="small">Negative Keywords optional eine Zeile gleich ein negativer Suchbegriff</label>
<textarea id="negatives" placeholder="z. B. billig kostenlos" style="min-height:60px"></textarea>
</div>
<div class="controls">
<button class="btn" id="btnGenerate">Generieren</button>
<button class="btn secondary" id="btnPreview">Vorschau</button>
<button class="btn ghost" id="btnCopy">Alle kopieren</button>
<button class="btn ghost" id="btnDownloadTxt">Als TXT herunterladen</button>
<button class="btn ghost" id="btnDownloadCsv">Als CSV herunterladen</button>
</div>
<div class="hint">Tipp: Lade eine einfache Textdatei mit einer Zeile pro Keyword hoch oder füge die Liste direkt ein.</div>
</div>
<div style="margin-top:12px;">
<div class="stats" id="statsRow" aria-live="polite">
<div class="badge" id="statInput">0 Keywords</div>
<div class="badge" id="statGenerated">0 Ergebnisse</div>
<div class="badge" id="statDuplicates">0 Duplikate</div>
</div>
</div>
</div>
<div class="card">
<label>Ergebnisse</label>
<div id="results" class="result-list">
<div class="muted">Keine Ergebnisse. Klicke Generieren oder Vorschau.</div>
</div>
<div class="export-row">
<button class="btn" id="btnExportJson">Alle als JSON exportieren</button>
<button class="btn secondary" id="btnExportFiltered">Gefilterte CSV</button>
<button class="btn secondary" id="btnRemoveAll">Alles löschen</button>
</div>
<hr style="margin:12px 0;border:none;border-top:1px solid #f1f5f9" />
<label>Optional AJAX Upload</label>
<div style="margin-top:8px">
<div style="display:flex;gap:8px;align-items:center">
<input id="uploadUrl" type="url" placeholder="https://example.com/api/upload" style="flex:1" />
<button class="btn" id="btnUpload">Upload starten</button>
</div>
<div class="hint">Wenn du eine Ziel URL angibst werden die aktuellen Ergebnisse per POST an die angegebene URL gesendet. Format JSON { keywords [...], generated [...] }</div>
</div>
</div>
</div>
<div class="card" style="margin-top:18px;">
<h3 style="margin:0 0 8px 0">Wie es funktioniert</h3>
<ol>
<li>Keywords einfügen oder Datei hochladen eine Zeile gleich ein Keyword</li>
<li>Match Types auswählen Exact Phrase Broad Modifier Broad</li>
<li>Optionen anpassen Duplikate entfernen Kleinbuchstaben</li>
<li>Generieren Ergebnisse prüfen kopieren oder herunterladen</li>
<li>Optional Ergebnisse per AJAX an deinen Server senden</li>
</ol>
<p class="hint">Der Generator verarbeitet alle Daten lokal im Browser es sei denn du nutzt den optionalen Upload.</p>
</div>
<div class="card" style="margin-top:18px;">
<h4 style="margin:0 0 8px 0">Beispiel</h4>
<pre>schuhe kaufen
lederschuhe
sportschuhe herren
best laufschuhe</pre>
<div class="hint">Ausgabe für Broad Modifier mind 2 Wörter: <code>+schuhe +kaufen</code> <code>+sportschuhe +herren</code></div>
</div>
<div class="card" style="margin-top:18px;">
<h4 style="margin:0 0 8px 0">Einschränkungen</h4>
<ul>
<li>Generator ergänzt Zeichen für Match Types auf Basis einfacher Regeln prüfe generierte Listen vor Einsatz</li>
<li>Broad Modifier nur auf Keywords mit mindestens der eingestellten Wortanzahl angewandt</li>
<li>Beim Upload an einen Server verwende HTTPS und sichere die Server API</li>
</ul>
</div>
<div class="footer">
<div class="small">Fragen oder besondere Anforderungen Kontaktiere Dreamcodes</div>
<div style="display:flex;gap:8px">
<a class="small" href="https://dreamcodes.net" target="_blank" rel="noopener noreferrer">dreamcodes.net</a>
</div>
</div>
<footer class="site">
<p class="footer-note">
Hinweis Die Verarbeitung geschieht ausschließlich im Browser. Die Dateien werden nicht ohne dein Zutun an einen Server gesendet. Mehr Infos bei
<a href="https://dreamcodes.net" target="_blank" rel="noopener noreferrer">Dreamcodes.net</a>.
</p>
<p style="margin-top:8px;font-size:12px;color:var(--muted)">© Dreamcodes</p>
</footer>
</div>
<script>
// Elemente
const inputKeywords = document.getElementById('inputKeywords');
const btnChoose = document.getElementById('btnChoose');
const fileInput = document.getElementById('fileInput');
const btnClear = document.getElementById('btnClear');
const btnGenerate = document.getElementById('btnGenerate');
const btnPreview = document.getElementById('btnPreview');
const btnCopy = document.getElementById('btnCopy');
const btnDownloadTxt = document.getElementById('btnDownloadTxt');
const btnDownloadCsv = document.getElementById('btnDownloadCsv');
const optExact = document.getElementById('optExact');
const optPhrase = document.getElementById('optPhrase');
const optBroadMod = document.getElementById('optBroadMod');
const optBroad = document.getElementById('optBroad');
const optRemoveDups = document.getElementById('optRemoveDups');
const optLowercase = document.getElementById('optLowercase');
const bmMinWords = document.getElementById('bmMinWords');
const negatives = document.getElementById('negatives');
const results = document.getElementById('results');
const statInput = document.getElementById('statInput');
const statGenerated = document.getElementById('statGenerated');
const statDuplicates = document.getElementById('statDuplicates');
const btnExportJson = document.getElementById('btnExportJson');
const btnExportFiltered = document.getElementById('btnExportFiltered');
const btnRemoveAll = document.getElementById('btnRemoveAll');
const uploadUrl = document.getElementById('uploadUrl');
const btnUpload = document.getElementById('btnUpload');
const dropzone = document.getElementById('dropzone');
let parsedInput = []; // array of strings
let generated = []; // array of strings
let duplicatesCount = 0;
// Hilfsfunktionen
function normalizeLine(line){
return line.replace(/\r/g,'').trim();
}
function splitLines(text){
if(!text) return [];
return text.split(/\n/).map(normalizeLine).filter(l=>l.length>0);
}
function uniqueArray(arr){
const seen = new Set();
const out = [];
let dup=0;
for(const i of arr){
if(seen.has(i)){ dup++; continue; }
seen.add(i);
out.push(i);
}
return {arr: out, duplicates: dup};
}
function download(filename, content, mime='text/plain'){
const blob = new Blob([content], {type:mime});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
a.remove();
URL.revokeObjectURL(url);
}
// Datei einlesen
btnChoose.addEventListener('click', ()=> fileInput.click());
fileInput.addEventListener('change', async e => {
const f = e.target.files[0];
if(!f) return;
try {
const text = await f.text();
inputKeywords.value = inputKeywords.value ? (inputKeywords.value + '\n' + text) : text;
updateInputStats();
} catch(err){
alert('Fehler beim Lesen der Datei ' + (err.message || err));
}
fileInput.value = '';
});
// Drag und Drop
['dragenter','dragover'].forEach(evt=>{
dropzone.addEventListener(evt, e=>{
e.preventDefault();
dropzone.classList.add('dragover');
});
});
['dragleave','drop'].forEach(evt=>{
dropzone.addEventListener(evt, e=>{
e.preventDefault();
dropzone.classList.remove('dragover');
});
});
dropzone.addEventListener('drop', async e=>{
const dt = e.dataTransfer;
const files = Array.from(dt.files||[]);
if(files.length===0) return;
for(const f of files){
try{
const text = await f.text();
inputKeywords.value = inputKeywords.value ? (inputKeywords.value + '\n' + text) : text;
} catch(err){
// ignore
}
}
updateInputStats();
});
// Status aktualisieren
function updateInputStats(){
const lines = splitLines(inputKeywords.value || '');
parsedInput = lines;
statInput.textContent = `${lines.length} Keywords`;
statGenerated.textContent = `${generated.length} Ergebnisse`;
statDuplicates.textContent = `${duplicatesCount} Duplikate`;
}
// Kernerzeugung
function generateList(){
generated = [];
duplicatesCount = 0;
let list = splitLines(inputKeywords.value || '');
const negs = splitLines(negatives.value || '');
if(optLowercase.checked){
list = list.map(s=>s.toLowerCase());
}
if(optRemoveDups.checked){
const {arr, duplicates} = uniqueArray(list);
list = arr;
duplicatesCount = duplicates;
}
for(const kw of list){
const clean = kw.replace(/\s+/g,' ').trim();
if(clean.length === 0) continue;
if(optExact.checked){
generated.push('[' + clean + ']');
}
if(optPhrase.checked){
generated.push('"' + clean + '"');
}
if(optBroadMod.checked){
const words = clean.split(/\s+/);
const minWords = Math.max(1, Number(bmMinWords.value) || 1);
if(words.length >= minWords){
const bm = words.map(w=>{
return '+' + w.replace(/^[+\-\"\[\]]+|[+\-\"\[\]]+$/g,'');
}).join(' ');
generated.push(bm);
} else {
if(optBroad.checked){
generated.push(clean);
}
}
}
if(optBroad.checked){
generated.push(clean);
}
}
if(negs.length){
for(const n of negs){
const cleanN = n.replace(/\s+/g,' ').trim();
if(cleanN.length === 0) continue;
generated.push('-' + cleanN);
}
}
if(optRemoveDups.checked){
const {arr, duplicates} = uniqueArray(generated);
generated = arr;
duplicatesCount += duplicates;
}
updateInputStats();
renderResults();
}
// Darstellung der Ergebnisse
function renderResults(){
results.innerHTML = '';
if(!generated.length){
results.innerHTML = '<div class="muted">Keine Ergebnisse. Generiere zuerst die Liste.</div>';
statGenerated.textContent = '0 Ergebnisse';
return;
}
statGenerated.textContent = `${generated.length} Ergebnisse`;
for(let i=0;i<generated.length;i++){
const it = generated[i];
const div = document.createElement('div');
div.className = 'result-item';
const left = document.createElement('div');
left.textContent = it;
const right = document.createElement('div');
right.style.display = 'flex';
right.style.gap = '8px';
const cbtn = document.createElement('button');
cbtn.className='btn secondary';
cbtn.style.fontWeight=700;
cbtn.textContent='Kopieren';
cbtn.onclick = async ()=>{
await navigator.clipboard.writeText(it);
cbtn.textContent='Kopiert';
setTimeout(()=>cbtn.textContent='Kopieren',1000);
};
const removeBtn = document.createElement('button');
removeBtn.className='btn ghost';
removeBtn.textContent='Entfernen';
removeBtn.onclick = ()=>{
generated.splice(i,1);
renderResults();
};
right.appendChild(cbtn);
right.appendChild(removeBtn);
div.appendChild(left);
div.appendChild(right);
results.appendChild(div);
}
}
// Button Aktionen
btnGenerate.addEventListener('click', ()=>{
try {
generateList();
} catch(e){
alert('Fehler beim Generieren ' + (e.message || e));
}
});
btnPreview.addEventListener('click', ()=>{
// schnelle Vorschau erzeugen
try {
generateList();
} catch(e){
alert('Fehler bei der Vorschau ' + (e.message || e));
}
});
btnClear.addEventListener('click', ()=>{
if(!confirm('Felder wirklich leeren')) return;
inputKeywords.value = '';
negatives.value = '';
generated = [];
parsedInput = [];
duplicatesCount = 0;
renderResults();
updateInputStats();
});
btnCopy.addEventListener('click', async ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Kopieren'); return; }
await navigator.clipboard.writeText(generated.join('\n'));
alert('Alle Ergebnisse in die Zwischenablage kopiert');
});
btnDownloadTxt.addEventListener('click', ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Herunterladen'); return; }
download('keywords.txt', generated.join('\n'), 'text/plain');
});
btnDownloadCsv.addEventListener('click', ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Herunterladen'); return; }
const csv = generated.map(s => '"' + s.replace(/"/g,'""') + '"').join('\n');
download('keywords.csv', csv, 'text/csv');
});
btnExportJson.addEventListener('click', ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Exportieren'); return; }
const payload = { input: parsedInput, generated, options: {
exact: optExact.checked, phrase: optPhrase.checked, broadModifier: optBroadMod.checked, broad: optBroad.checked,
removeDuplicates: optRemoveDups.checked, lowercase: optLowercase.checked, bmMinWords: Number(bmMinWords.value) || 1
}};
download('keywords.json', JSON.stringify(payload, null, 2), 'application/json');
});
btnExportFiltered.addEventListener('click', ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Exportieren'); return; }
// Gefilterte CSV: Trenne nach Typ
const rows = generated.map(s => {
let type = 'broad';
if(s.startsWith('[') && s.endsWith(']')) type = 'exact';
else if(s.startsWith('"') && s.endsWith('"')) type = 'phrase';
else if(s.startsWith('+')) type = 'broad_modifier';
else if(s.startsWith('-')) type = 'negative';
return `"${s.replace(/"/g,'""')}","${type}"`;
}).join('\n');
const header = '"keyword","type"\n';
download('keywords_filtered.csv', header + rows, 'text/csv');
});
btnRemoveAll.addEventListener('click', ()=>{
if(!confirm('Alle Ergebnisse wirklich löschen')) return;
generated = [];
parsedInput = [];
duplicatesCount = 0;
inputKeywords.value = '';
negatives.value = '';
renderResults();
updateInputStats();
});
// AJAX Upload
btnUpload.addEventListener('click', async ()=>{
if(!generated.length){ alert('Keine Ergebnisse zum Hochladen'); return; }
const url = uploadUrl.value.trim();
if(!url){ alert('Bitte Ziel URL angeben'); return; }
try{
const payload = { input: parsedInput, generated, options: {
exact: optExact.checked, phrase: optPhrase.checked, broadModifier: optBroadMod.checked, broad: optBroad.checked,
removeDuplicates: optRemoveDups.checked, lowercase: optLowercase.checked, bmMinWords: Number(bmMinWords.value) || 1
}};
const resp = await fetch(url, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if(!resp.ok){
const text = await resp.text();
throw new Error('Upload fehlgeschlagen Status ' + resp.status + ' ' + text);
}
alert('Upload erfolgreich');
} catch(err){
alert('Fehler beim Upload: ' + (err.message || err));
}
});
// initial
updateInputStats();
renderResults();
</script>
</body>
</html>