A visual snapshot across every workflow and account -- see the Results tab for the detailed, filterable send log. Click a number, segment, or bar below to see the underlying sends.
Project revenue
Open & click rate
Send outcome
Emails sent per day
Workflow performance
Account sending volume
Account health
Enrollment funnel (all workflows)
Contact → Lead → Customer pipeline
Leads by status
Customer engagement mix
Warm-up progress
Lists
Group contacts into lists, then associate a list with the Workflow tab so adding someone to that list is what triggers the email sequence.
| List name | Contacts |
|---|
Add contacts
CSV or Excel (.xlsx/.xls), any columns — firstname, lastname, email, mobile, company are matched automatically; anything else (title, industry, LinkedIn URL, ...) you can map to a custom field on the next step and use in your emails. Header row required; column order doesn't matter. Which list(s) these contacts join is chosen on the next screen, right before they're actually imported.
Additional details (optional — same fields as the sample CSV; each becomes a {{placeholder}} you can use in emails)
Map your columns
We matched what we could automatically. For anything else, choose a system field, map it to a custom field (usable in your emails as {{fieldname}}), or leave it out. First name/Last name/Email/Mobile/Company can each only be used once — if you have more than one column of the same kind of data (e.g. several phone numbers), map the rest to their own custom fields so nothing gets silently discarded.
⚠️ No column is mapped to Email yet — pick one below (a contact can't be imported without an email address).
| Your file's column | Sample value | Maps to | Custom field name |
|---|
Add these contacts to a list
Some of these already exist
For each, choose what to do with the incoming row:
| Existing | Incoming | Action |
|---|
Contacts (0)
| Name | Mobile | Company | Lists | Enrollments | Status | |||
|---|---|---|---|---|---|---|---|---|
LinkedIn Outreach
No LinkedIn credentials are ever entered here. This finds a likely LinkedIn profile via Apollo (a licensed contact-data lookup), helps you draft a message, and -- only once you approve it -- opens that person's real LinkedIn profile in a new tab so you can paste and send it yourself. Nothing is ever sent automatically.
Matched profile
Wrong person, or no match found? Fix it directly via the ✏️ Edit action on this contact instead -- the LinkedIn profile URL is one more editable field there.
Draft message
Approve & send
Sending itself always happens on LinkedIn's own site, by you.
Contacts flagged as a potential deal (use the Convert to Lead button on the Contacts tab). Move a lead through Qualification → Discovery → Proposal → Negotiation, then close it Won (becomes a Customer) or Lost (a reason is required).
Leads (0)
| Name | Company | Status | Lead since |
|---|
Lead
Convert to Customer
This currency carries forward to the Customer's own engagement details until explicitly changed there.
Close as Lost
Follow-up
Activity
Closed-won leads, with engagement details for reference across the team.
Customers (0)
| Name | Company | Engagement | Contract value | Start date | Account manager |
|---|
Customer
Statements of Work
Standard boilerplate legal terms are included automatically. This is not legal advice -- have counsel review before sending a real client a contract.
AI-assisted drafting
Pick which AI to use for "Fill via AI" on your SOWs -- each provider needs its own key, saved once here, to your own account only.
Google AI Studio's Gemini API has a genuine free tier.
- Open your browser and go to Google AI Studio.
- Sign in using your standard Google account.
- Accept the API terms of service when prompted.
- Click on Get API key located in the side menu.
- Click Create API key and select an existing project or let it generate a new one.
- Copy the generated key and paste it below.
OpenAI's API has no free tier -- pick this only if you already have (or don't mind paying for) an OpenAI account.
- Open your browser and go to OpenAI's API keys page.
- Sign in (or create an account) and add a billing method -- required for API access.
- Click Create new secret key.
- Copy the generated key and paste it below.
A genuinely free, self-hosted option that needs no API key at all -- not built yet. This will run locally (or, once this app moves to real hosting, in the cloud) rather than through a third party, so there's no key to bring and no per-use cost. Use Gemini (free) or ChatGPT (your own paid key) in the meantime.
| Title | Status | Created |
|---|
New SOW
Fills in your real Outsourcing Services Agreement template -- view/edit and save while it's a draft, then Generate and View the PDF before sending it to the client.
Fill via AI
No AI key saved yet -- set one up above (Gemini or ChatGPT), then pick "Fill via AI" again.
Provider (your own) details on this Agreement
Exhibit A -- Statement of Work details
Pre-filled from your template's own standard wording -- edit any row's description as needed for this engagement.
Invoices
| Number | Status | Issue date | Due date | Total |
|---|
New Invoice
Line items
| Description | Qty | Rate | Amount |
|---|
Provider (your own) details on this invoice
Workflows
Every workflow you've created, active or draft. Only Active ones actually enroll and email contacts. "Rejected" is an SMTP-rejection proxy (the mail server refused the address at send time) -- this app doesn't parse bounce or reply email, so there's no true bounce/reply detection behind those-style columns.
| Activate | Name | Trigger list | Account | Enrolled | Not Sent | Scheduled | Finished | Paused | Rejected | Delivered | Opened | Clicked | % Complete | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Edit workflow
Viewing only — every field here is locked. Open "Edit" from the "⋯" menu instead to make changes.
Email 1 sends as soon as a contact is added to the trigger list. Then each following email waits the number of days you set below. All three go out from whichever account you pick above.
If a day isn't checked, no step goes out that day for this workflow — contacts due that day just wait until the next checked day. Unchecking all days means this workflow never sends.
Outside this window, this workflow sits out entirely (same idea as "Send on these days") — contacts due just wait for the window to reopen. A start/end time only takes effect once a timezone is picked too — with no timezone selected, this workflow sends any time, matching "leave blank" above.
When on, every email after the first goes out as a real reply to the one before it — same subject line as the first email (prefixed "Re:"), proper email threading headers, and the previous email quoted underneath. If someone missed or ignored an earlier email, opening a later one shows them exactly what it said. Applies from here on — anyone already partway through this workflow before you turn it on won't have earlier history to quote, so their follow-ups still send as independent emails.
Sequence
Any mix of email, wait, and task steps, in any order, any length. The very first step fires as soon as a contact is added to the trigger list; everything after it waits however long you set a wait step for (days or minutes). All emails go out from whichever account you picked above; a task step creates a to-do on the Tasks tab for someone to complete manually, but doesn't hold up the sequence -- the contact moves straight on to whatever's next.
Placeholders you can use in an email's subject/body: {{firstname}} {{lastname}} {{company}} {{email}} {{mobile}} — spelling variants like {{first_name}} or {{First Name}} work too. Anything else in {{double braces}} that isn't one of these is left untouched (so a typo shows up instead of silently disappearing). Custom fields from an upload (see the Contacts tab) show up here automatically once you've imported at least one.
Tasks
Everything a workflow or a lead follow-up asks you to do by hand, in one place: calls, reminders and LinkedIn outreach. The contact's progress through the workflow does not wait on these. For a LinkedIn task, click Work on it to open the message, the LinkedIn page and the safety meter right here; setup, limits and history are on the Outreach Setup tab.
| Contact | Workflow | Task | Created | |||
|---|---|---|---|---|---|---|
Open & click tracking
Requires a public URL this app is reachable at — a tracking pixel/link pointing at localhost is invisible to a real recipient's mail client. Leave this blank while running locally; fill it in once you deploy somewhere with a real domain, and tracking turns on automatically for every email sent after that.
Worth knowing even once this is on: open tracking is industry-wide unreliable — Apple Mail Privacy Protection pre-loads images in every email regardless of whether it's actually opened, and some providers proxy/cache images too. Treat opens as a rough directional signal; clicks are a much stronger sign of real engagement.
Default sender mailing address
The CAN-SPAM Act requires a valid physical postal address in every commercial email you send. Shown in the same footer as the unsubscribe link, on every campaign email — never in your warm-up mail, since that's just between your own mailboxes. This is the default, used by any account that hasn't set its own -- if you run campaigns from mailboxes belonging to different business entities or domains, set each one's own address instead on that account's own editor ("Sender Mailing Address" step).
Company letterhead (SOW / Invoice PDFs)
Applied automatically to every generated SOW and Invoice, like a real printed letterhead -- a colored header band with your company name (and logo, if you upload one) on the first page only, and a footer with your address/website/phone on the last page only. Company name and address are reused from the "Default sender mailing address" card above.
Email accounts
Every mailbox you can send from. Tag each workflow to one of these on the Workflow tab — different workflows can send from different accounts.
| Name | From email | Configured | Daily limit | Warm-up | Health | Used by |
|---|
Edit account
Viewing only — every field here is locked. Open "Edit" from the table instead to make changes.
This is the mailbox campaign emails sent from this account will come from -- either via your own mailbox's SMTP credentials, or connected directly through Microsoft (below) so nothing is typed in at all.
How should this account send email?
Best if this mailbox is a personal Gmail address or a Google Workspace account. Signs you in on Google's own real login page -- if this account uses Google Prompt or another 2-Step Verification method, you'll see and approve it right there. Nothing is typed in here, and you never need to generate or paste an app password.
Google sign-in isn't configured on this server yet -- ask your Performdesk admin to set it up, or use "Via SMTP" instead in the meantime.
Best if this mailbox is on Microsoft 365 or Outlook.com -- especially if your organization's IT department has "Security Defaults" or a Conditional Access policy turned on, which silently blocks plain SMTP sign-in for business accounts (a common wall). This connects directly through Microsoft Graph instead, which those policies don't affect at all.
If "Link with Microsoft" shows "Need admin approval", your organization's Microsoft 365 admin needs to approve this once for everyone -- use the button above to copy a link for them.
Best for any other provider (Zoho, a custom business domain, etc.), or if Google/Microsoft account linking isn't set up on this server yet. You'll need this mailbox's own SMTP host and port, plus a password -- often a separate "app password" your provider generates, not your normal login password.
Steps to configure the mailbox itself
- Prefer the 🔗 Link with Google tab above instead, if it's showing -- no host/port/password to get right, and no app password to generate.
- If linking isn't available yet: turn on 2-Step Verification on your Google account (Google Account → Security).
- Go to Google Account → Security → App passwords, create one for "Mail".
- Use host
smtp.gmail.com, port587, security STARTTLS. - Username = your full Gmail address. Password = the 16-character app password (not your normal login password).
- Prefer the 🔗 Link with Microsoft tab above instead, if it's showing -- no host/port/password to get right, and it isn't affected by a tenant's Security Defaults or Conditional Access policies the way this manual SMTP path can be.
- If linking isn't available yet: use host
smtp.office365.com, port587, security STARTTLS. - Username = your full Outlook/Microsoft 365 email address.
- If your tenant enforces MFA, create an app password under Microsoft account → Security instead of your normal password.
- Use host
smtp.zoho.com(or your regional domain, e.g.smtp.zoho.in). - Port
587with STARTTLS, or port465with SSL/TLS. - In Zoho Mail, enable 2FA and generate an app-specific password under My Account → Security → App Passwords, and use that as the password here.
- Username = your full Zoho email address.
- Ask your email/IT provider for their outgoing SMTP host and port.
- Pick STARTTLS for ports 587/25, or SSL/TLS for port 465.
- Username/password are the mailbox login credentials for that provider's SMTP server.
How long to wait between two emails sent from this account — e.g. 1, 2, 5, 10... The scheduler checks every minute, so this is the minimum spacing, not an exact clock. Applies no matter which method above this account sends through.
Test this account
Without these DNS records, mail can get accepted by your own server (looks "sent" in this app) but silently dropped or spam-foldered by the recipient's provider. DKIM is generated and signed by this app itself; SPF/DMARC are DNS records you add. (These records are SPF / DKIM / DMARC -- the standard trio recipient providers check to trust mail is really from your domain.)
Blocklist status
Checks this account's mail server against major public spam blocklists (DNSBL/RBL) -- if it's listed, mail from it can get silently dropped or spam-foldered by providers like Gmail even with clean SPF/DKIM. On-demand only; doesn't run automatically.
Builds genuine inbox activity by exchanging realistic business emails between your own accounts (never with real contacts) — spread across morning/afternoon/evening, at least 5 minutes apart no matter how many accounts are sending, so nothing arrives in a burst. Sending and receiving are separate switches, so an account can do either, both, or neither — e.g. check only "Send" on an account you don't care about receiving mail into, just to generate warm-up traffic for the accounts you do care about.
Where do you want a copy of sent campaign emails?
This account sends via Microsoft Graph ("Link with Microsoft"), which already automatically files every sent campaign email into this mailbox's real Sent Items folder as part of sending -- there's nothing to set up on this tab for a linked account.
This account sends via the Gmail API ("Link with Google"), which already automatically files every sent campaign email into this mailbox's real Sent label as part of sending -- there's nothing to set up on this tab for a linked account.
Plain SMTP sending never leaves a trace in the mailbox on its own — pick where you'd like this app to leave one.
Puts a copy in this mailbox's INBOX so there's something to check right away — the simplest option, works everywhere, no extra settings.
Plain SMTP sending (what this app does) never touches your mailbox's folders — it only hands the message to the mail server for delivery. This connects via IMAP right after each send and files an identical copy into this mailbox's real Sent folder, the same extra step a normal email client does. Uses the same username/password as SMTP above.
Leave IMAP host blank to reuse the SMTP host above -- correct for most single-server setups. "Fill in <provider>'s SMTP settings" on the Account Details tab fills in all three of these correctly too, once a provider is detected.
Sender mailing address for this account
The CAN-SPAM Act requires a valid physical postal address in every commercial email. Different accounts often belong to different business entities or domains running their own campaigns, so each account can set its own address here instead of your tenant-wide default (set on the Email Accounts tab, above the accounts table).
Sending standards & why they matter
This tool follows the same guardrails cold-outreach platforms (Apollo, Zoho, Instantly, Lemlist, etc.) build in, so a mailbox doesn't get rate-limited or blacklisted:
- One email at a time per account, spaced by the "Send every" minutes you set (1 by default). The scheduler checks every minute and only sends when that account is actually due — never a burst. Providers flag mailboxes that suddenly fire off dozens of emails in the same second.
- A daily cap per account, shared across every active workflow that sends from it (not a separate budget per workflow) — because reputation is tied to the mailbox. 30–50/day is the safe range for a mailbox with no warm-up history; 50–150/day once the domain has weeks of consistent, low-bounce sending behind it. Start near the low end on a new domain and raise it gradually week over week.
- Follow-ups are prioritized over new outreach. If an account's daily budget can't cover both, contacts already partway through a sequence (waiting on Email 2/3) get sent before brand-new contacts start Email 1.
- Keep bounce rate low. Clean/verify your list where you can — a high bounce rate is one of the fastest ways to damage sender reputation, independent of volume.
- SPF/DKIM/DMARC configured for your sending domain (see below, per account) — without this, mail can get accepted by your own server (looks "sent") but silently dropped or spam-foldered by the recipient's provider.
Account sending volume
| Account | From email | Configured | Sent today / daily limit | Warm-up today |
|---|
Workflow performance
| Workflow | Trigger list | Account | Status | Enrolled | Completed | Pending | Failed | Opened | Clicked | Replied |
|---|
Send log
The scheduler checks every minute and sends at most one email per account per check (see Email Accounts → Sending standards) — that's what paces sends and enforces each account's daily cap. "Send next one now" runs one check immediately instead of waiting up to a minute, handy for testing.
| Time | Type | Contact | Workflow | Step | Status | Message | Opens | Clicks |
|---|---|---|---|---|---|---|---|---|
Outreach Setup
Set up how Performdesk reaches people beyond email. Your day-to-day LinkedIn to-dos are on the Tasks tab.
LinkedIn Outreach
Assisted mode: you press Send every timePerformdesk reaches people on LinkedIn in the way you choose below. In the default Assisted mode it never signs in to LinkedIn and never sends for you: you press Send yourself, which is the lowest-risk way to use LinkedIn outreach.
Your LinkedIn to-dos are on the Tasks tab.
Safety guide: how to avoid LinkedIn limits (read this first)
Do
- Use your own account, from your own computer and your normal internet connection.
- Stay under the daily budget shown below. Stop when the meter turns amber or red.
- Send only to people who plausibly want to hear from you, with a short, honest, personal note.
- Wait about 3 to 5 minutes between items. Do not rush.
- Reply to people yourself, promptly. Anyone who replies should not be contacted again from here.
- Withdraw old pending invitations from time to time (LinkedIn: My Network, Manage, Sent).
Do not
- Do not run other LinkedIn automation tools or browser extensions on the same account.
- Do not use a VPN, proxy or cloud computer for this account.
- Do not raise your limits to "catch up" after a pause.
- Do not send the same message to hundreds of strangers, or anything misleading.
- Do not ignore a warning from LinkedIn. If you see "weekly limit reached" or a security check, stop for the day and wait a few days before sending again.
- Do not share your LinkedIn or Performdesk login with anyone.
No setting can make LinkedIn outreach completely risk-free: LinkedIn limits connection requests per week no matter who clicks Send. These budgets are set well under what we have seen LinkedIn tolerate. This is guidance, not legal advice.
Your LinkedIn account and today's budget
Adjust my limits (you can lower them freely; raising is capped at a safe ceiling)
How should Performdesk work on LinkedIn?
Assisted is the safest and is on for everyone: you press Send every time. Guided and Autonomous use a small program on your own computer that drives your own browser. LinkedIn prohibits that kind of automation, so each needs your written acknowledgment first.
Recovery checklist
The bot stopped because of a LinkedIn warning. Do not try to work around it. Read and tick every box before it can resume.
1. Connect LinkedIn Not connected
Before you connect your LinkedIn account, please read this agreement to the end. You sign in to LinkedIn yourself, at your own risk.
The agreement is accepted. To sign in to LinkedIn, Performdesk uses a small program on your own computer that opens Chrome. Your LinkedIn password is typed only into LinkedIn, by you, and your signed-in session stays on your computer.
- Download the Performdesk LinkedIn app (.zip) and unzip it somewhere permanent (for example your Documents folder).
- Open the unzipped
workerfolder and double-clicksetup-worker. It installs what it needs (it tells you if Chrome or Node.js is missing). - Your web browser opens Performdesk and asks you to press Connect. Check that the page shows your own Performdesk account (if it shows someone else, use "Not you?" on that page). Then a Chrome window opens: sign in to LinkedIn there.
This page updates by itself when it is connected. Already installed? Double-click start-worker instead. On a Mac, or if you prefer to do it by hand, use the advanced steps below.
LinkedIn connected
Advanced: connect with a code or a key
The normal way is the Connect button in your browser. These are for a Mac, a computer without a default browser, or support.
- Run
node linkedin-worker.js --pair CODEin the worker folder. It works once and expires in 10 minutes. - The key is shown once. Save it where only you can read it (the box below gives a one-line command), then run
node linkedin-worker.js.
Copy this key now. It will not be shown again. Anyone who has it can control your bot, so do not share it.
2. Dry run Not run
Before the first start, the worker visits each person's page, checks it is the right person and prepares each message, without sending anything. You review the list and approve it.
3. Plan, schedule and pace
Gap between actions: a random 3 to 5 minutes, with a longer break every 8 to 12 actions. The daily and weekly limits are the ones in the budget below, scaled down while the bot is new (40% in week 1, 70% in week 2).
Recent stops and notices
Do and do not (for the bot)
Do
Do not
Optional: let a browser helper type your messages
The helper is installed but switched off, so nothing will be typed for you yet. Click the puzzle-piece icon in your browser toolbar (pin Performdesk LinkedIn Fill Assist so it stays visible), click it, tick Type my message into LinkedIn, then reload this page. It stays off until you do this yourself.
Optional: fill-assist helper Checking…
A small browser extension that types your message into the LinkedIn box for you, so you do not need to paste. It is off by default. It only types into an empty box on the right person's page. It never presses Send, never opens pages on its own, and never reads your clipboard. Without it, the message is copied for you to paste, which works the same.
- Click Download the helper and unzip it (right-click, Extract All). You get a folder named
performdesk-linkedin-helper. Keep it somewhere permanent: the browser loads the extension from that folder every time it starts. - Click Copy the extensions address, open a new tab, paste it in the address bar and press Enter. (Browsers do not let a web page open this page for you.) Turn on Developer mode.
- Click Load unpacked and choose the unzipped folder. This is a one-time step, and a browser never lets a website do it for you.
- Turn it on (it is off until you do): click the puzzle-piece icon in your browser toolbar and pin Performdesk LinkedIn Fill Assist so it stays visible. Click it and tick Type my message into LinkedIn.
- Reload this page. The badge above should say On. If it says "Installed, turned off", the box in the previous step is not ticked yet. If it says "Not installed", the helper is not loaded or is not allowed for this address (see the last step).
- If you open Performdesk at an address other than
http://localhost:3000, add that address in the extension's Settings.
LinkedIn changes its page layout from time to time. If the helper ever stops typing, just paste with Ctrl+V (or Cmd+V): the copy always happens.
Check against LinkedIn's Sent list (finds requests that did not really go through)
LinkedIn sometimes drops a connection request without any warning, most often after you reach its weekly limit. This check compares the requests you marked as sent with the people on your LinkedIn Sent invitations page. Anyone missing is flagged and is not counted toward your limits until you decide what happened. It needs the optional fill-assist helper (see above), turned on. It only reads names and "Sent ... ago" on that one page, and only while you run a check.
Accepted invitations leave the Sent list, so a person who already accepted can show up here as "not found". If that is the case, choose "They accepted it". Only requests from the last 21 days are checked. Messages and InMail cannot be checked this way.
Recent activity (what you did on LinkedIn, newest first)
How this works
The Contacts tab's "LinkedIn Outreach" action (and a workflow's own LinkedIn step) look up a contact's real LinkedIn profile by email. Add your own API key for one or more providers below -- we try them in the order you set, top to bottom, stopping at the very first one that finds a real profile. Your key is yours alone: no other tenant's usage ever touches your account's credits, and your key is never visible to anyone but you.
A real cost to be aware of: most of these are paid, credit-metered commercial APIs -- they typically offer a limited number of free lookups per month, then bill (or simply stop working) once that's used up. Check your own account's plan with each provider before relying on heavy usage; this app has no way to track or cap your spending with any of them.
Your providers
Reorder with the arrows to change which provider gets tried first. A provider with no key saved (or turned off) is simply skipped, at no cost.
Your match performance
Which of your own providers is actually bringing in LinkedIn contacts. This card never triggers a new lookup, and doesn't auto-refresh while you're looking at it -- use the button above after matching a few more contacts to see updated numbers.
Raise a ticket
Tell us what is wrong or what you need. We reply right here, and you will see a number on the Support tab when we have. Include what you expected to happen and what happened instead.
Your tickets
Looking for the right people for a client's requirement? Enter the skills and limits below. Best matches come first, with the matching skills highlighted.
Find candidates
| Name | Title | Location | Exp. | Notice | Expected comp. | Skills | Status | Pipeline | Updated |
|---|
Getting started
Everyone you have added. Click a status to filter, tick people to change several at once, or open one to edit their details, make a client-ready CV and keep their history.
| Name | Title | Location | Exp. | Notice | Expected comp. | Skills | Status | Pipeline | Updated |
|---|
Upload CVs
Upload one or more CVs (PDF, DOCX or TXT, up to 5 MB each, 20 at a time). Each is scanned for contact details, skills, experience and education, and becomes a candidate. If the same person is already on file (same email or phone), you are asked what to do: nothing is added twice by accident.
Waiting for your decision
These uploads match someone already on file. Nothing has been saved yet. Review each one and choose to skip it, update the existing record, or keep it as a separate record. Uploads left here for 14 days are discarded.
Add a candidate by hand
No CV to upload? Enter the basics here. You can add the rest, and upload a CV later, from the candidate's page.
A quick picture of your candidate pool. For how candidates are moving through each client project (technical and managerial rounds, sent to client), open the Projects dashboard.
CVs by status
Click a bar to see those candidates.
CVs added per week
Tagged to a project
Most common skills
CV formats
A CV format is how a client-ready CV looks: header, footer, colors and company details. Most companies need just one. The default format is used for every candidate who does not have their own.
Add a CV format: how do you want to start?
1 Upload your existing CV format
The easiest way. Upload a PDF or Word file of your own CV format (a sample CV or a blank template). A PDF gives us its header, footer and colors. A Word file gives us its heading color, section order and wording, logo and website; client CVs are always PDFs for now.
Want exact control in a Word file? Use placeholders.
Type these where the details should appear, for example {{name}}: name, title, employer, location, years, notice, qualification, summary, skills, email, phone, linkedin, expected_ctc, current_ctc, benefits, today. For lists, put one of {{skills_list}}, {{experience_list}}, {{education_list}}, {{certifications_list}} on a line of its own. Email, phone and compensation are filled in only when you allow them.
2 Design one
Pick a style, a color, your company details and a logo. Good when you have no existing format to copy.
3 Upload letterhead images
Each PNG or JPEG (up to 3 MB) becomes its own format, named after the file, with the image as its header banner. Choose several at once.
New format
PNG or JPEG. The header banner runs across the top of the first page (about 1700 x 200 pixels works well); the footer image runs across the bottom of the last page. They replace the style's own header and footer.
Assign formats to individual candidates (optional)
Most companies use one format for everyone and can skip this. Choose a format for each candidate, or tick several and set them together. "Default" means the candidate follows whichever format is the default.
| Candidate | Title | Status | CV format |
|---|
Your company details
Formats use these unless a format sets its own. They are the same details your SOWs and invoices use, so they are set in one place.
Candidate
If this person turned out to be a proxy (someone else attended the interview), or should be blocked or blacklisted, say so here. It takes effect at once.Your sourcing head decides, and the history records it.
Choose the project and the position (skill) this candidate is being put forward for.
Earlier tags
Make a client-ready CV
Three steps. Nothing is sent to anyone: you download the file and send it yourself.
Summary table for the client email
-
1Choose the format
-
2Choose what to include
-
3Preview, then download
Open the PDF in a new tab (if it does not show above)
-
4Copy the summary table for the email
The details table that goes in the email with the CV. Paste it into your email and it stays a table.
Extra fields for this projectSkill ratings table
The candidate's own rating next to the technical panel's, both out of 10. Copy it with the table above and send both with the CV.
Original CV (as uploaded)
Revenue placements (a SOW or an external project this person bills on)
| Project | Client | Role | Status | Rate | Dates |
|---|
Keep this person's supporting files here: a resignation or relieving letter, ID proof, payslips, an offer letter, recordings, spreadsheets, or the original email. They stay inside Performdesk, are never put on a client CV, and everyone who works on candidates can download them. Choose what kind of file it is, then upload.
| Type | File | Size | Added | Note |
|---|
How candidates are moving through each project: sourced, technical interview, managerial interview, sent to the client, and the client's decision. Click any number to see the people behind it.
Needs attention
Candidates waiting on someone right now. Click one to see who.
Sourcing funnel
By position
Each position's own numbers. Click a position to focus the whole dashboard on it, or click a number to see the people.
| Position | Sourced | Technical | Managerial | Sent to client | Client | |||
|---|---|---|---|---|---|---|---|---|
| Interviewed | Passed | Interviewed | Passed | Selected | Rejected | |||
CVs sourced per week
Who is sourcing
| Person | Sourced | Passed technical | Passed managerial | Sent to client | Client selected |
|---|
Candidates
| Candidate | Position | Technical | Managerial | Sent | Client | Where it stands |
|---|
Projects
A project is what a client wants: the positions to fill, the budget, the JD and any client-specific requirements. Candidates are tagged to a project and position as you source them.
New project
Each position is a role the client wants (for example Scrum Master, .NET Developer, DevOps) with its own budget, onsite or offshore, shift, location, benefits, duration, date needed and JD. Candidates are tagged to a position. Use Duplicate to start a similar position and change only what differs.
Project
Waiting for approval
Both internal interviews were positive. Check the profile and the feedback, then approve it so it can go to the client.
Ready to send to the client
Approved profiles. Download the CV in the company format, copy the client table, send them, then mark each one as sent.
Sent, waiting for the client
Record the client's decision when it comes. Everyone on the project then sees it.
Selected: offer and joining
The client chose these candidates. Keep the offer and the joining up to date; the sourcing team stays in touch until they join. Open one to record the offer, the answer, or the joining.
Sourcing team
Create a login
Who works on what
Each person with the positions assigned to them. Hold an assignment to pause it (they still see it, but cannot tag candidates to it), or detach it to take them off. The numbers show how loaded each person is.
| Name | Role | Status | Last sign-in |
|---|
Assign work
Choose one or more people, then the positions they should work on. Use "all open positions" to give someone a whole project at once.
Flag requests
A teammate proposes marking a candidate as a proxy, blocked or blacklisted. Approving writes it to the candidate's history and stops them being tagged.
Your company's hiring workspace
Loading...
Recent changes
Rate card
Management onlyWhat the company bills per hour for each role and experience band, and the company-wide numbers behind every position's budget. A project can apply its own discount and margin on top (Projects, edit a project, Commercials). When anything here changes, every budget and every candidate's margin changes with it.
Loading...
Your plan
Products
Performdesk Core -- the full Contact-to-Customer journey -- is free forever. Add-ons below unlock extra tabs and capabilities for a monthly fee.
Subscribe
Choose how you'd like to pay -- you'll be redirected to a secure, hosted checkout page. Performdesk never sees or stores your card details.
Invoices
| Date | Product | List | Discount | Amount due | Status |
|---|
Payment methods
| Provider | Card | Expires | Default |
|---|
A payment method is added automatically the first time you subscribe to a paid product.
Billing notifications
Super Admin
Cross-tenant view — every user's data, read-only. Your own Contacts / Workflow / Results / Tasks tabs are unaffected by this and still show only your own account.
Users & activity summary
| Role | Verified | Sign-in method | Online now | Last login | Contacts | Lists | Workflows | Active | Accounts | Sent | Failed | Tasks | Pending | Joined | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
All contacts (every user)
| Owner | Name | Mobile | Company | List(s) | Workflow status | |
|---|---|---|---|---|---|---|
All workflows (every user)
| Owner | Workflow | Status | Enrolled | Sent | Failed |
|---|---|---|---|---|---|
Open & click rate
Send outcome
Emails sent per day
Tenant performance
Contacts per tenant
Enrollment funnel (every workflow, every tenant)
All results (every user, most recent 1000)
| Owner | Time | Type | Contact | Workflow | Status | Message | Opens | Clicks |
|---|---|---|---|---|---|---|---|---|
All tasks (every user)
| Owner | Contact | Workflow | Task | Status | Created |
|---|---|---|---|---|---|
Overview
Payment provider credentials
A provider only shows up as a checkout option on a tenant's own Billing tab once its real credentials are saved here -- until then, "Subscribe" correctly says "No payment provider is configured yet." These write-only fields never show a previously saved secret back (same convention as an email account's own SMTP password) -- to change any one field later, re-enter ALL of that provider's fields and save again; a partial resubmit isn't supported. Real Stripe/PayPal/Square developer accounts are required -- get test-mode credentials from that provider's own dashboard first.
Dodo is the seller of record: it collects and pays the sales tax and handles card disputes. Create the keys in the Dodo dashboard (Developer, API keys) and a webhook (Developer, Webhooks) pointing at with the events subscription.* and payment.succeeded. Leave a field blank to keep what is already saved.
Product catalog
Performdesk Core is the free flagship, auto-granted to every signup -- its list price is shown on every tenant's own invoice as a 100% discount, never actually charged. Every other row is a paid add-on; toggle "Active" once its real feature is actually built and ready to sell.
| Product | List price | Charged price | Active | Live subs |
|---|
Discounts
Drives Performdesk's own invoice records and reporting. A discount meant to actually reduce what a payment provider charges must also be created on that provider's own dashboard (Stripe Coupons, etc.) using the same code.
| Code | Description | Amount | Plan | Redemptions | Active |
|---|
New discount
Subscriptions (every tenant)
| Tenant | Product | Provider | Status | Started | Renews / ends |
|---|
Support tickets
| # | Subject | User | Topic | Status | Last update |
|---|
Business details
Shown on the public Privacy, Terms, Refunds, Contact and Data deletion pages that the footer links to. Until you save a business name, the pages say "Performdesk"; until you save a support email, they point people to the Support tab.
Send the app's own emails from your domain
Sign-up verification and notice emails go out as noreply@performdesk.com instead of the relay mailbox's own address, signed with your domain's DKIM key (the same method Clipper360 uses). No mailbox is needed on performdesk.com: the mail still travels through the existing mailbox's server. Steps: save the addresses, press Create signing key, add the three DNS records in Cloudflare, press Check DNS until all three are OK, send yourself a test, then tick "Send this way" and save.
LinkedIn-matching providers: read-only oversight
LinkedIn-matching API keys moved to a per-tenant, self-service setting -- every signed-in user manages their own provider keys/order on their own Integrations tab now, with no shared credentials and no admin gate. This panel is oversight only: aggregate match performance across every tenant, and how many tenants have actually set anything up.
LinkedIn match performance
Which provider is actually bringing in LinkedIn contacts -- across every tenant by default, or pick one tenant above to see just their own breakdown. Counts here reflect whatever matching has already happened elsewhere in the app (a workflow's own LinkedIn step, or a manual/bulk refresh) -- this card itself never triggers a new lookup, and doesn't auto-refresh while you're looking at it, so use the Refresh button after matching a few more contacts to see the updated numbers. "Unknown" is a contact that already had a LinkedIn profile URL before this tracking existed, so there's genuinely no record of which provider (if any) found it -- not guessed into any real provider or "Manual". "Unmatched" has no LinkedIn profile URL at all yet.