Start with the jobs. Find the right reach.

Add your job descriptions and hiring goals. Get audience guidance, media budget options, a campaign-readiness check, and a branded plan to share with your team.

Your next campaign starts here.

Put your open roles, audience decisions and investment in one plan. Share it with your team or continue to campaign setup.

01 · HIRING NEEDS

Tell us what you're hiring for.

Add a company website, job link or as many priority roles as you need. Explore your plan before creating an account.

Roles and hiring goals

02 · AUDIENCE

Who needs to see these jobs?

Audience planning starts with the role and relevant professional qualifications. Choose the candidate channels to explore for each role.

How to reach promising candidates

Choose the digital channels that fit your audience and hiring need.

Paid advertising is separate from standard job posting. Final placement options and pricing appear during campaign setup.

03 · CAMPAIGN INVESTMENT

Compare the options before you spend.

Compare investment levels based on your roles, hiring targets and campaign timeline.

Add a role to calculate your plan.
Adjust the investment to see how the campaign mix and pacing could change.
04 · BEFORE LAUNCH

Make sure the candidate journey works.

Check the details that determine whether paid traffic becomes useful recruiting activity.

0 of 10 verified

05 · YOUR PLAN

Here’s your starting recommendation.

Share it with your team, adjust it, or continue to the authenticated campaign workflow.

Your presentation brings together the jobs, audience, investment and launch details you've selected.

When you're ready, continue to Talent Magnet Workspace to review campaign setup, terms and funding.
+Math.round(r.meanAnnualWage).toLocaleString('en-US'):'No unambiguous occupational mapping yet')+'

'+e(r.limitation||'')+'

'+(r.occupation?'View official source ↗':'')+'').join('')+'

Publisher inventory, location-level candidate availability, historical application rates and media costs require separate verified sources. These figures do not set the ad budget automatically.

'; S.researchReady=true; }catch(error){target.innerHTML='
National occupation research could not load. Continue your plan; it does not depend on this lookup.
'} } $('refresh-research').addEventListener('click',()=>{S.researchSig='';occupationResearch()}); const signature=()=>JSON.stringify([jobs(),$('pace').value,$('days').value]); async function estimate(){ const a=jobs();if(!a.length)return;const sig=signature();if(S.estimate&&S.estimate.sig===sig){renderBudget();return} $('budget-alert').className='note warn';$('budget-alert').textContent='Building an investment estimate by role…'; try{const rows=await Promise.all(a.map(async j=>{const res=await fetch('/api/estimate',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({role:j.title,location:j.where,positions:j.hires,days:Number($('days').value),pace:$('pace').value})});const x=await res.json();if(!x.ok)throw Error(x.error||'Unable to calculate');return {...x,title:j.title,hires:j.hires}}));S.estimate={sig,rows,minimum:rows.reduce((s,x)=>s+x.minimum,0),recommended:rows.reduce((s,x)=>s+x.recommended,0),higherReach:rows.reduce((s,x)=>s+x.higherReach,0)};if(!S.budget)S.budget=S.estimate.recommended;renderBudget()}catch(err){$('budget-alert').textContent='Could not calculate at the moment. Your job entries remain available here.';$('budget-body').hidden=true}} function renderBudget(){const o=S.estimate;if(!o)return;$('budget-body').hidden=false;$('budget-alert').className='note';$('budget-alert').textContent='Illustrative planning estimates. The final funded total and inventory are confirmed during campaign setup.';for(const x of ['minimum','recommended','higherReach'])$(x).textContent=money(o[x]);$('range').max=Math.max(o.higherReach*1.35,o.recommended+2000);$('range').value=Math.min(S.budget,+$('range').max);$('job-breakdown').innerHTML='

Recommended by role

'+o.rows.map(x=>'

'+e(x.title)+' · '+x.hires+' hire(s) · '+money(x.recommended)+'

').join('');spend()} function spend(){if(!S.estimate)return;$('funding').textContent=money(S.budget);$('custom-budget').value=S.budget;const a=details(),totalHires=jobs().reduce((s,x)=>s+x.hires,0);$('funnel').innerHTML='

'+money(S.budget/Math.max(1,totalHires))+' per requested hire

'+(a.rate?'At your own '+a.rate+'% application-to-hire conversion rate, you would need roughly '+Math.ceil(totalHires*100/a.rate)+' applications to reach your hiring goal. This is a requirement calculation, not a forecast.':'Enter your historical application-to-hire rate if you know it. We will not invent an application forecast.')+'

';const weights={'Programmatic job advertising':50,'Paid search':25,'Paid social':20,'Specialist publisher audiences':5},total=a.channels.reduce((s,x)=>s+(weights[x]||10),0);$('mix').innerHTML=total?a.channels.map(x=>{const p=(weights[x]||10)/total*100;return '
'+e(x)+'
'+money(S.budget*p/100)+'
'}).join(''):'
Choose at least one channel first.
';side()} $$('[data-scenario]').forEach(b=>b.addEventListener('click',()=>{if(!S.estimate)return;S.budget=S.estimate[b.dataset.scenario];renderBudget();stash()}));$('range').addEventListener('input',v=>{S.budget=Number(v.target.value);spend();stash()});$('custom-budget').addEventListener('change',v=>{S.budget=Math.max(250,Number(v.target.value)||250);spend();stash()});$('rate').addEventListener('input',spend);$$('#channels input').forEach(x=>x.addEventListener('change',()=>{spend();stash()})); $('checks').addEventListener('change',()=>{const n=$$('#checks input:checked').length;$('bar').style.width=(n*10)+'%';$('count').textContent=n+' of 10 verified';side();stash()}); function report(){const a=jobs(),d=details(),notDone=checkNames.filter((v,i)=>!d.checks.includes(i));$('report').innerHTML='
TALENT MAGNET · HIRING PLAN

Hiring needs

'+a.map(x=>'').join('')+'
RoleLocationHires
'+e(x.title)+''+e(x.where||'To confirm')+''+x.hires+'

'+e(d.pace)+' priority · '+d.days+' days · '+e(d.problem)+'

Audience

Skills: '+e(d.skills||'To confirm')+'. Related occupations: '+e(d.adjacent||'To confirm')+'.

Channels: '+e(d.channels.join(', ')||'To confirm')+'.

Investment

Planned amount: '+money(S.budget)+'. '+(S.estimate?'Recommended starting model: '+money(S.estimate.recommended)+'.':'Final amount pending.')+'

Candidate experience

'+e(d.experience.replaceAll('_',' '))+' · '+e(d.ats||'ATS not supplied')+'

Before launch

'+d.checks.length+'/10 checks verified. '+(notDone.length?'Still to check: '+e(notDone.slice(0,3).join('; ')):'All marked complete, subject to technical validation.')+'

Planning estimates are not quotes or guarantees. Publisher access and campaign funding need confirmation.

'} window.__tmGetPlan=()=>({jobs:jobs(),settings:details(),budget:S.budget,estimate:S.estimate,derived:deriveAudience()}); $('save').addEventListener('click',async()=>{const a=jobs(),d=details(),out=$('save-result');if(!a.length){step(0);return}$('save').disabled=true;out.innerHTML='
Saving your plan…
';try{const payload={role:a[0].title,location:a[0].where,positions:a.reduce((s,x)=>s+x.hires,0),days:d.days,pace:d.pace,url:d.url,jobs:a,analysis:S.analysis,estimate:S.estimate,source_path:'/plan',objective:d.objective,problem_hint:d.problem,application_experience:d.experience,application_platform:d.ats,app_to_hire_pct:d.rate,readiness:d.checks,budget_override:S.budget,skills:d.skills,adjacent:d.adjacent,channels:d.channels};const res=await fetch('/api/plan',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify(payload)}),r=await res.json();if(!r.ok)throw Error(r.error||'Plan could not be saved');S.ref=r.id;const href=location.origin+'/plan?ref='+r.id;out.innerHTML='
Plan saved. Keep this link to revisit or share it.
Open plan
';$('copy').addEventListener('click',async()=>{try{await navigator.clipboard.writeText(href);$('copy').textContent='Copied'}catch{prompt('Copy this link',href)}})}catch(err){out.innerHTML='
'+e(err.message)+' You can still print the plan.
'}finally{$('save').disabled=false}}); $('scan').addEventListener('click',async()=>{const val=$('website').value.trim(),out=$('scan-result');if(!val){out.innerHTML='
Enter a public website or job URL.
';return}$('scan').disabled=true;out.innerHTML='
Checking the page…
';try{const res=await fetch('/api/inspect',{method:'POST',headers:{'content-type':'application/json'},body:JSON.stringify({url:val})}),r=await res.json();S.analysis=r;if(!r.ok)out.innerHTML='
'+e(r.error)+' Continue by entering the job details below.
';else {out.innerHTML='

'+e(r.jobTitle||r.title||r.hostname)+'

'+e(r.description||'No page description available')+'

Job description: '+(r.jobDescription?'Extracted from '+e(r.jobSource):'Not available in public HTML')+' · HTML forms: '+Number(r.formsFound||0)+'

A preview, not a complete ATS or browser form audit.

';const item=S.jobs[0];if(item){if(r.jobDescription&&(!item.description||item.description.length<100))item.description=r.jobDescription;if(r.jobTitle&&(!item.title||item.title.length<4))item.title=r.jobTitle;if(r.jobDescription)item.url=val;jobUI();if(r.jobDescription)applyAudience(false)} }}catch{out.innerHTML='
The site could not be inspected automatically. Enter the hiring need manually.
'}finally{$('scan').disabled=false;stash()}}); for(const id of ['website','pace','days','problem','skills','adjacent','objective','experience','ats'])$(id).addEventListener('change',()=>{S.estimate=null;side();stash()}); hydrate();if(!S.jobs.length)S.jobs=defaultJobs();jobUI();if(query.get('url'))$('website').value=query.get('url'); async function getSaved(){const id=query.get('ref');if(!id)return;try{const res=await fetch('/api/plan?id='+encodeURIComponent(id)),r=await res.json();if(!r.ok)throw Error();const p=r.plan;S.jobs=p.jobs?.length?p.jobs.map(j=>({id:crypto.randomUUID(),title:j.title||j.role||'',where:j.where||j.location||'',hires:j.hires||j.positions||1,url:j.url||''})):[{id:crypto.randomUUID(),title:p.role,where:p.location||'',hires:p.positions||1,url:''}];jobUI();for(const [id,k] of [['pace','pace'],['days','days'],['problem','problem_hint'],['website','site_url'],['skills','skills'],['adjacent','adjacent'],['objective','objective'],['experience','application_experience'],['ats','application_platform'],['rate','app_to_hire_pct']])if(p[k]!=null)$(id).value=p[k];$$('#channels input').forEach(x=>x.checked=(p.channels||[]).includes(x.value));$$('#checks input').forEach(x=>x.checked=(p.readiness||[]).includes(Number(x.value)));S.budget=Number(p.budget_override)||0;step(4);$('save-result').innerHTML='
Saved plan loaded. Saving changes will produce a new link.
'}catch{$('scan-result').innerHTML='
The saved plan could not be loaded. You can start a new one.
'}} getSaved();if(!query.get('ref')&&['budget','audiences'].includes(location.pathname.slice(1)))step(location.pathname==='/budget'?2:1); side(); })();