Du hittar en bra jobbannons, och sedan tappar du en timme på att copy-pasta beskrivningen till anteckningar, justera ett cv, exportera PDF:er och leta upp filen “final_final_v3” senare.
Den här automatiseringen för cv-PDF drabbar jobbsökare först, helt ärligt. Men karriärcoacher som hanterar flera klienter och rekryteringsbyråer som stöttar kandidater känner samma röra: utspridda versioner, inkonsekvent formatering och för mycket manuellt admin.
Det här flödet tar en jobbannons som skickas i Telegram och gör den till ett anpassat cv och personligt brev, och sparar sedan den polerade PDF:en i Google Drive (och loggar allt i Google Sheets). Du får se vad det gör, vad du behöver och hur du undviker de vanliga fallgroparna vid uppsättning.
Så fungerar automatiseringen
Hela n8n-flödet, från trigger till slutresultat:
n8n Workflow Template: Telegram till Google Drive: proffsiga cv-pdf:er
flowchart LR
subgraph sg0["Telegram Incoming Flow"]
direction LR
n5["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Telegram Incoming Trigger"]
n6@{ icon: "mdi:robot", form: "rounded", label: "Resume Letter AI", pos: "b", h: 48 }
n7["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/code.svg' width='40' height='40' /></div><br/>JSON to HTML Mapper"]
n8["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/html.dark.svg' width='40' height='40' /></div><br/>HTML Template Builder"]
n9["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/github.dark.svg' width='40' height='40' /></div><br/>GitHub File Update"]
n10@{ icon: "mdi:database", form: "rounded", label: "Append Sheet Entry", pos: "b", h: 48 }
n11@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Mini Chat", pos: "b", h: 48 }
n12@{ icon: "mdi:memory", form: "rounded", label: "Session Memory Store", pos: "b", h: 48 }
n13@{ icon: "mdi:cog", form: "rounded", label: "Experience Data Tool", pos: "b", h: 48 }
n14@{ icon: "mdi:robot", form: "rounded", label: "Application JSON Parser", pos: "b", h: 48 }
n9 --> n10
n6 --> n7
n8 --> n9
n14 -.-> n6
n12 -.-> n6
n5 --> n6
n13 -.-> n6
n11 -.-> n6
n7 --> n8
end
subgraph sg1["Chat Message Flow"]
direction LR
n21@{ icon: "mdi:play-circle", form: "rounded", label: "Chat Message Trigger", pos: "b", h: 48 }
n22@{ icon: "mdi:robot", form: "rounded", label: "Experience Structuring AI", pos: "b", h: 48 }
n23@{ icon: "mdi:cog", form: "rounded", label: "Insert Experience Row", pos: "b", h: 48 }
n24@{ icon: "mdi:brain", form: "rounded", label: "OpenAI Chat Engine", pos: "b", h: 48 }
n25@{ icon: "mdi:memory", form: "rounded", label: "Context Memory Buffer", pos: "b", h: 48 }
n26@{ icon: "mdi:robot", form: "rounded", label: "Structured JSON Parser", pos: "b", h: 48 }
n22 --> n23
n25 -.-> n22
n24 -.-> n22
n26 -.-> n22
n21 --> n22
end
subgraph sg2["Flow 3"]
direction LR
n0["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/webhook.dark.svg' width='40' height='40' /></div><br/>Inbound Webhook"]
n1["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/httprequest.dark.svg' width='40' height='40' /></div><br/>External PDF Request"]
n2@{ icon: "mdi:cog", form: "rounded", label: "Drive File Upload", pos: "b", h: 48 }
n3@{ icon: "mdi:database", form: "rounded", label: "Upsert Sheet Record", pos: "b", h: 48 }
n4["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/telegram.svg' width='40' height='40' /></div><br/>Telegram Status Note"]
n0 --> n1
n2 --> n3
n1 --> n2
n3 --> n4
end
subgraph sg3["Manual Start Flow"]
direction LR
n15@{ icon: "mdi:play-circle", form: "rounded", label: "Manual Start Trigger", pos: "b", h: 48 }
n16@{ icon: "mdi:swap-vertical", form: "rounded", label: "Asset Code Set", pos: "b", h: 48 }
n18["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/github.dark.svg' width='40' height='40' /></div><br/>CSS File Commit"]
n19["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/github.dark.svg' width='40' height='40' /></div><br/>Index File Commit"]
n20["<div style='background:#f5f5f5;padding:10px;border-radius:8px;display:inline-block;border:1px solid #e0e0e0'><img src='https://flowpast.com/wp-content/uploads/n8n-workflow-icons/github.dark.svg' width='40' height='40' /></div><br/>Workflow YML Commit"]
n18 --> n19
n16 --> n18
n19 --> n20
n15 --> n16
end
subgraph sg4["Flow 5"]
direction LR
n17@{ icon: "mdi:cog", form: "rounded", label: "Node_17", pos: "b", h: 48 }
end
%% Styling
classDef trigger fill:#e8f5e9,stroke:#388e3c,stroke-width:2px
classDef ai fill:#e3f2fd,stroke:#1976d2,stroke-width:2px
classDef aiModel fill:#e8eaf6,stroke:#3f51b5,stroke-width:2px
classDef decision fill:#fff8e1,stroke:#f9a825,stroke-width:2px
classDef database fill:#fce4ec,stroke:#c2185b,stroke-width:2px
classDef api fill:#fff3e0,stroke:#e65100,stroke-width:2px
classDef code fill:#f3e5f5,stroke:#7b1fa2,stroke-width:2px
classDef disabled stroke-dasharray: 5 5,opacity: 0.5
class n5,n21,n15 trigger
class n6,n14,n22,n26 ai
class n11,n24 aiModel
class n12,n25 ai
class n10,n3 database
class n0,n1 api
class n7 code
classDef customIcon fill:none,stroke:none
class n5,n7,n8,n9,n0,n1,n4,n18,n19,n20 customIcon
Problemet: versionskaos och formateringsstrul i cv:t
Att anpassa ansökningar fungerar, men arbetsflödet runt det är brutalt. Du börjar med en jobbannons i en flik, ditt “grund-cv” i en annan och en mall för personligt brev någon annanstans. Sedan kommer alla små beslut som dränerar dig: vilka kompetenser som ska lyftas, vilken formulering som ska speglas, vad som ska bort för att få plats på en sida och hur du håller allt konsekvent. Lägg till export till PDF, filnamn och att spara på ett ställe där du faktiskt hittar det senare. Gör du det några gånger i veckan blir det ett extrajobb.
Det eskalerar snabbt. Här är var det faller isär i verkligheten:
- Du skriver om samma punktlistor för “relevant erfarenhet” från grunden för varje jobbannons.
- PDF-exporterna ser lite olika ut varje gång, vilket leder till formateringsfixar i sista minuten precis innan du skickar in.
- Filer namnges inkonsekvent och sparas i slumpmässiga mappar, så du kan inte snabbt återanvända det som fungerade.
- Det finns ingen strukturerad historik över vilket cv och personligt brev som skickades till vilket företag, så uppföljningar känns röriga.
Lösningen: Telegram → anpassat cv som PDF, autosparas i Drive
Det här n8n-flödet ger dig ett enda, repeterbart input: skicka jobbannonsen till en Telegram-bot. Därifrån hämtar en AI-agent din sparade erfarenhet (roll, sammanfattning, arbetsuppgifter, kompetenser, verktyg, bransch) från en n8n-datatabell och använder den som förankrad kontext för anpassningen. Den genererar strukturerat innehåll för ansökan, mappar in det i en HTML-mall för cv och publicerar HTML:en till GitHub Pages så att den kan renderas konsekvent. Sedan konverterar Gotenberg den hostade HTML:en till en PDF, och n8n sparar det färdiga cv:t som PDF i Google Drive. Till sist loggar den företaget och de genererade dokumenten i Google Sheets och skickar ett “Klart”-meddelande så att du inte råkar lägga överlappande förfrågningar i kö.
Flödet startar med en Telegram-meddelandetrigger. I mitten omvandlar AI-agenten och OpenAI:s chattmodell din erfarenhetsdatabas plus jobbannonsen till felfri, strukturerad output, och sedan bygger en mapper den slutliga HTML:en. Slutresultatet är en PDF som sparas i Drive (plus en rad i Sheets) som håller sig organiserad utan extra arbete.
Det du får: automatisering kontra resultat
| Vad det här flödet automatiserar | Resultat du får |
|---|---|
|
|
Exempel: så ser det ut i praktiken
Säg att du söker 5 jobb på en vecka. Manuellt betyder en “anpassad” ansökan ofta cirka 45 minuter med att skriva om punkter, 20 minuter på personliga brevet och 10 minuter på att exportera/byta namn/ladda upp PDF:en, alltså ungefär 6 timmar totalt. Med det här flödet klistrar du in jobbannonsen i Telegram (cirka 5 minuter) och väntar sedan några minuter på generering och PDF-rendering medan du gör något annat. Du granskar fortfarande resultatet, men grovjobbet är gjort, och din cv-PDF är redan sparad i Google Drive och loggad i Sheets.
Det här behöver du
- n8n-instans (prova n8n Cloud gratis)
- Alternativ för egen hosting om du föredrar det (Hostinger fungerar bra)
- Telegram för att skicka in jobbannonser snabbt
- Google Drive för att lagra de färdiga cv-PDF:erna
- Google Sheets för att logga ansökningar och resultat
- GitHub + GitHub Pages för att hosta HTML-cv:t inför konvertering
- Gotenberg för att konvertera hostad HTML till PDF:er
- OpenAI API-nyckel (hämta den i din OpenAI-dashboard)
Kunskapsnivå: Mellan. Du kopplar konton, klistrar in några nycklar och är bekväm med att kontrollera en körlogg när något fallerar.
Vill du inte sätta upp det här själv? Prata med en automationsexpert (gratis 15-minuters konsultation).
Så fungerar det
Ett Telegram-meddelande startar allt. Du klistrar in texten från jobbannonsen i Telegram, och flödet använder meddelandet som facit för vad som ska anpassas.
Din erfarenhet hämtas från din databas. AI-agenten frågar din n8n-datatabell (roll, sammanfattning, arbetsuppgifter, kompetenser, verktyg, bransch) så att cv och personligt brev baseras på din verkliga bakgrund, inte påhitt.
AI genererar strukturerat innehåll och bygger cv-filen. Flödet tolkar outputen till felfri JSON, mappar in den i en HTML-mall och committar uppdateringar till GitHub så att senaste versionen alltid finns tillgänglig via GitHub Pages.
PDF:en hamnar i Google Drive och spåras. Gotenberg konverterar den hostade HTML:en till en PDF, n8n laddar upp den till Drive, skriver sedan en rad i Google Sheets och skickar ett Telegram-meddelande med “Klart”.
Du kan enkelt ändra cv-mallen och namngivningsreglerna så att de matchar din stil och ditt arkiveringssystem. Se hela implementationsguiden nedan för anpassningsalternativ.
Steg-för-steg-guide för implementation
Steg 1: konfigurera webhook-triggern
Sätt upp den inkommande webhooken och synka den efterföljande request-kedjan som genererar PDF:er och startar CV-flödet.
- Lägg till och konfigurera Inbound Webhook med Path satt till
fc896fbb-4a70-48d2-a416-564a3eeeae91. - Koppla Inbound Webhook till External PDF Request och ställ in URL till
http://000.00.00:3000/forms/chromium/convert/url, Method till POST och Content Type tillmultipart-form-data. - I External PDF Request lägger ni till en body-parameter med namnet url och värdet
https://evenkik.github.io/Resume_url/för att generera CV-PDF:en. - Bekräfta att exekveringsflödet kör Inbound Webhook → External PDF Request → Drive File Upload utan parallella grenar.
Steg 2: koppla Google Drive och Sheets
Koppla lagring och loggning för den genererade CV-PDF:en och ansökningsposter.
- Öppna Drive File Upload och ställ in Name till
=resume-{{ $json.body.message }}.pdf, välj sedan era Drive- och Folder-ID:n. - Inloggning krävs: Anslut era
googleDriveOAuth2Api-uppgifter i Drive File Upload. - Konfigurera Upsert Sheet Record med Operation satt till
appendOrUpdate, Document satt till[YOUR_ID]och Sheet satt tillgid=0. - Mappa kolumner i Upsert Sheet Record: resume till
{{ $json.webContentLink }}, company till{{ $('Inbound Webhook').item.json.body.message }}och surat-lamaran till=. - Inloggning krävs: Anslut era
googleSheetsOAuth2Api-uppgifter i Upsert Sheet Record och Append Sheet Entry. - I Append Sheet Entry ställer ni in Operation till
appendoch mappar fält till{{ $('Telegram Incoming Trigger').item.json.message.link_preview_options.url }},{{ $('Resume Letter AI').item.json.output.company }},{{ $('Resume Letter AI').item.json.output.application_letter }}och{{ $('Resume Letter AI').item.json.output.job_description }}.
[YOUR_ID] i Drive File Upload, Upsert Sheet Record och Append Sheet Entry med era faktiska Drive-mapp- och Google Sheet-ID:n.
Steg 3: sätt upp Resume Letter AI
Konfigurera AI-flödet för generering av CV och brev, inklusive minne, verktyg och strukturerad output.
- Konfigurera Telegram Incoming Trigger för att ta emot message-uppdateringar från er bot.
- Inloggning krävs: Anslut era
telegramApi-uppgifter i Telegram Incoming Trigger och Telegram Status Note. - I Resume Letter AI ställer ni in Text till
{{ $json.message.text }}och behåller Prompt Type som define med Has Output Parser aktiverat. - Bekräfta att OpenAI Mini Chat är ansluten som språkmodell för Resume Letter AI och använder modellen
gpt-5-mini. - Inloggning krävs: Anslut era
openAiApi-uppgifter i OpenAI Mini Chat. - Verifiera att AI-undernoder är kopplade till Resume Letter AI: Session Memory Store med Session Key satt till
{{ $json.message.from.id }}, Experience Data Tool med Operationgetoch Return All aktiverat, samt Application JSON Parser med det angivna JSON-schemat.
Steg 4: konfigurera output- och publiceringsnoder
Transformera AI-output till HTML och publicera den till GitHub, och logga sedan ansökan i Sheets.
- I JSON to HTML Mapper behåller ni den medföljande JavaScript-koden som bygger HTML för skill och tool och trimmar LinkedIn-URL:er från Telegram Incoming Trigger.
- Koppla JSON to HTML Mapper till HTML Template Builder och behåll HTML-mallen i fältet HTML.
- Konfigurera GitHub File Update med File Path
docs/index.html, File Content{{ $json.html }}och Commit Message{{ $('Resume Letter AI').item.json.output.company }}. - Inloggning krävs: Anslut era
githubApi-uppgifter i GitHub File Update, CSS File Commit, Index File Commit och Workflow YML Commit. - Bekräfta att exekveringsflödet kör HTML Template Builder → GitHub File Update → Append Sheet Entry i den ordningen.
https://github.com/ och repot Job-apply i GitHub-noderna med er faktiska ägare och repo.
Steg 5: konfigurera inmatning för erfarenhetsstrukturering
Den här vägen strukturerar ostrukturerad erfarenhetstext till en datatabell för återanvändning vid anpassning av CV.
- Sätt upp Chat Message Trigger för att ta emot inkommande text för erfarenhetsbearbetning.
- Konfigurera Experience Structuring AI med Has Output Parser aktiverat och behåll reglerna i systemmeddelandet intakta.
- Säkerställ att OpenAI Chat Engine är ansluten som språkmodell för Experience Structuring AI och använder modellen
gpt-5. - Inloggning krävs: Anslut era
openAiApi-uppgifter i OpenAI Chat Engine. - Koppla Context Memory Buffer till Experience Structuring AI med Context Window Length satt till
10. - Använd Structured JSON Parser för output-schemat och mappa resultaten till fält i Insert Experience Row som Role, Tasks, Skills och industry med uttryck som
{{ $json.output.role }}.
Steg 6: konfigurera publicering av assets via GitHub-commits
Publicera statiska assets och workflow-filer via en manuell trigger och kedjade GitHub-commits.
- Använd Manual Start Trigger för att starta publiceringsflödet för assets när ni vill uppdatera CSS/HTML/YML-assets.
- I Asset Code Set behåller ni de fördefinierade värdena för tilldelningarna css, html och yml.
- Konfigurera CSS File Commit med File Path
docs/style.css, File Content{{ $json.css }}och Commit Message=style.css. - Konfigurera Index File Commit med File Path
docs/index.html, File Content{{ $json.html }}och Commit Messageindex.html. - Konfigurera Workflow YML Commit med File Path
github/workflows/notify-n8n.yml, File Content{{ $json['notify-n8n'].yml }}och Commit Message=notify-n8n.yml.
Steg 7: testa och aktivera ert workflow
Kör varje triggarväg för att verifiera end-to-end-beteendet innan ni aktiverar körning i produktion.
- Klicka Execute Workflow på Manual Start Trigger för att bekräfta att Asset Code Set → CSS File Commit → Index File Commit → Workflow YML Commit slutförs utan fel.
- Skicka ett testmeddelande till er bot för att trigga Telegram Incoming Trigger och verifiera att Resume Letter AI producerar JSON, att HTML byggs, att GitHub uppdateras och att Append Sheet Entry loggar posten.
- Skicka en test-webhook-request till Inbound Webhook och verifiera att PDF:en skapas, laddas upp av Drive File Upload och loggas av Upsert Sheet Record, följt av att Telegram Status Note skickar
Done.... - Bekräfta att lyckade körningar visar uppdaterade filer i GitHub, en ny PDF i Google Drive och tillagda rader i ert Google Sheet.
- När ni är redo växlar ni workflowet till Active så att webhook- och Telegram-triggers kör kontinuerligt.
Vanliga fallgropar
- Google Drive-inloggningar kan löpa ut eller kräva specifika behörigheter. Om det slutar fungera, kontrollera först n8n:s anslutningstest för autentiseringsuppgiften och dina åtkomstomfång i Google-kontot.
- Om du använder Wait-noder eller extern rendering varierar processtiderna. Öka väntetiden om nedströmsnoder fallerar på tomma svar.
- GitHub-commits kan misslyckas om din token inte kan skriva till Pages-grenen. Bekräfta repo-behörigheterna och att GitHub Pages är aktiverat för den gren som ditt flöde uppdaterar.
Vanliga frågor
Räkna med cirka 60 minuter när dina konton är klara.
Nej. Du kopplar mest konton och klistrar in några ID:n eller nycklar. “Kod”-delen finns redan inbyggd i flödet; du konfigurerar det bara.
Ja. n8n har ett gratisalternativ för egen hosting och en gratis provperiod på n8n Cloud. Cloud-planer börjar på 20 USD/månad för högre volym. Du behöver också räkna med OpenAI API-kostnader (oftast några cent per ansökan) och vad du än lägger på att hosta Gotenberg.
Två alternativ: n8n Cloud (hanterat, enklast uppsättning) eller egen hosting på en VPS. För egen hosting är Hostinger VPS prisvärt och hanterar n8n bra. Egen hosting ger dig obegränsade körningar men kräver grundläggande serverhantering.
Ja, och det bör du. Byt HTML:en i HTML Template Builder och justera JSON till HTML Mapper så att fälten hamnar där du vill ha dem. Många anpassar även filnamngivning (företag + roll + datum), ändrar målmapp i Google Drive och finjusterar AI-prompten så att den matchar deras skrivstil.
Oftast beror det på utgången OAuth-åtkomst eller saknade Drive-behörigheter i din Google-autentisering. Återanslut Google Drive-uppgiften i n8n och bekräfta sedan att målmappen fortfarande finns och att du fortfarande har åtkomst. Om uppladdningar fungerar ibland men inte alltid kan det också vara rate limiting när du kör flera ansökningar direkt efter varandra.
Om du kör n8n med egen hosting finns inget hårt tak för antal körningar; det beror främst på din server och hur lång tid PDF-renderingen tar.
För flerstegsgenerering av dokument är n8n oftast ett smidigare val eftersom det hanterar förgreningslogik, dataformning och flöden som “vänta på PDF:en, ladda upp, logga” utan att bli en skör kedja av mini-zaps. Du får också möjligheten att köra med egen hosting, vilket spelar roll när du gör många körningar eller vill ha tajtare kontroll över data. Zapier och Make kan fortfarande fungera, men komplexa AI + HTML-till-PDF-pipelines blir ofta dyra eller svåra att felsöka. Helt ärligt är den största fördelen insyn: n8n visar exakt var körningen misslyckades och vilken data som gick genom varje steg. Om du vill ha hjälp att välja, prata med en automationsexpert.
När detta väl är på plats slutar ansökningar kännas som ett filhanteringsprojekt. Flödet tar hand om de repeterbara delarna så att du kan fokusera på besluten som faktiskt spelar roll.
Kontakta oss
Hör av dig, så diskuterar vi hur just din verksamhet kan dra nytta av alla fantastiska möjligheter som AI skapar.