Skip to main content
Custom variables let you personalize outreach messages, interview settings, and workflows with data pulled from each job. Define a variable once, and Alex replaces its reference (for example {{custom:pay_rate}}) with the right value for each job whenever a template is sent. Custom variables come in two flavors:
  • LLM-generated: Alex reads the job description and extracts the value using a prompt you write.
  • ATS field: Alex pulls the value live from a specific field on an object in your ATS (Bullhorn, Salesforce, etc.).

Manage Your Custom Variables

Open Settings → Custom Variables (in the left sidebar under Interviews & Workflows) to see every variable defined for your company. Custom Variables settings page listing Role, Resume, and location variables with their references and descriptions Each row in the Job Fields table shows:
  • Label: the display name of the variable.
  • Variable: the reference you paste into a template - always of the form {{custom:<name>}}. The variable name is derived automatically from the label when you create the variable, so Pay Rate becomes {{custom:pay_rate}}.
  • Source: a short summary of where the value comes from - either the prompt (for LLM-generated variables) or the ATS field path (for ATS variables).
  • Actions: edit or delete the variable.
Click + Add Field in the top right to create a new one.

Add a Custom Variable

The Add Custom Field modal asks for a label, a source type, and the details that source type needs. Add Custom Field modal with the Label, Source Type (set to ATS Field), ATS Object, and ATS Field inputs Fill in:
  • Label: a short human-readable name (e.g. Pay Rate). The variable name is derived automatically - Pay Rate{{custom:pay_rate}}. You cannot change the variable name later, only the label, so pick a name you can live with.
  • Source Type: choose LLM Generated or ATS Field. The rest of the form changes based on what you pick.

LLM-generated variables

When Source Type is set to LLM Generated, the modal shows a Prompt textarea instead of ATS fields. Write a short instruction describing what Alex should extract from the job description. Good prompt examples:
  • Summarize the most important parts of the job description in 3 sentences or less.
  • Extract the hourly pay rate. Return only the number and currency (e.g. "$45/hr").

ATS field variables

When Source Type is ATS Field, fill in the ATS object and field that hold the value you want. The screenshot above shows this variant.
  • ATS Object: the parent object type in your ATS - for example JobOrder in Bullhorn or Job__c in Salesforce. Pick from the dropdown.
  • ATS Field: the exact field name on that object (e.g. customText26, Pay_Rate__c). The name must match your ATS exactly; misspellings silently return an empty string at send time.
ATS variables are fetched live from your ATS every time a template is rendered, so edits made in the ATS show up immediately - no refresh needed in Alex.

After you save

Click Add Field to create the variable. For LLM-generated variables, Alex immediately starts filling values for every active job in the background. Depending on your active jobs count, the initial backfill takes anywhere from a few seconds to a couple of minutes. ATS variables don’t need a backfill - they’re always live fetched.

Lock an LLM Variable

LLM-generated variables have a Lock toggle on the edit modal. Locking changes what happens to a variable’s value when a job description is edited.
  • Unlocked (default): When a job description changes, Alex automatically re-extracts the value for that job so it stays in sync with the latest JD.
  • Locked: When a job description changes, Alex leaves the existing value alone. Use this when a recruiter has manually cleaned up a value (or typed one in by hand) and you don’t want the next JD edit to overwrite their work.
A lock is a lock - once set, the value is protected from re-extraction. The only ways to change a locked variable’s value are:
  • Manually editing the value on the job’s settings page and clicking Save.
  • Editing the prompt in Settings → Custom Variables, which re-extracts every job regardless of lock state. Otherwise locked jobs would stay stuck on values generated by the old prompt.
Clicking Autofill on a locked variable from the job settings page returns an error asking you to unlock the variable in Settings first. Exception for new jobs: when a brand-new job is created, locked LLM variables are still populated on that job. The lock only protects existing values — there’s nothing to protect on a job that was just created, so the first-time fill runs normally. Locking is a property of the variable itself, not individual jobs - so it applies to every job at once. ATS-field variables don’t have a lock because their values are fetched live from the ATS and aren’t stored.

Review and Edit Values Per Job

On any job’s Settings tab, scroll to the Custom Variables section to see the values Alex has extracted and to edit them by hand. AI/ML Engineer job settings with a Custom Variables section showing Role, Resume, and location fields, each with an Autofill and Save button For each variable you can:
  • Type a value manually. Useful when the AI didn’t find what you wanted, or when the info isn’t in the JD. The input is a resizable textarea - drag the bottom-right corner to expand for longer values.
  • Click Autofill. Re-runs the AI extraction for that one field against the current job description.
  • Click Autofill All (top-right). Re-runs every AI-generated field on the job. You’ll be asked whether to skip already-filled fields or overwrite them.
  • Click Save. Persists a manual change. The Save button stays disabled until you actually modify the value.
Fields always show up in this list regardless of whether the AI found a value or errored out - so if a row is blank, you can decide whether to rewrite the prompt, click Autofill again, or fill it in by hand.

Use Variables in Workflows and Templates

Anywhere you write a message in Alex - workflow outreach emails, SMS, follow-up messages, interview settings - you’ll find a variable picker next to the formatting toolbar. Click it to browse and insert variables without memorizing the syntax. Workflow Outreach email editor with the variable picker open on the Custom tab, listing Role, Resume, and location as LLM generated variables The picker has three tabs:
  • All: every variable available for this template - defaults and customs together.
  • Default: built-in variables like {{company_name}} and {{position_title}}.
  • Custom: only the variables you created in Settings → Custom Variables. Each row shows the label, the variable name, and how the value is produced (LLM generated or the ATS field path).
Click any variable to insert it at the cursor. You can also type the variable directly: {{custom:your_variable_name}}. When the message is rendered, Alex replaces the variable with the value for that specific job.

Editing or Deleting a Variable

From Settings → Custom Variables, each row in the Actions column has edit and delete icons.
  • Editing the label only changes how the variable is displayed; the variable name ({{custom:...}}) stays the same, so existing templates keep working.
  • Editing the prompt (for LLM variables) kicks off a background re-extraction across all jobs so stored values match the new prompt.
  • Deleting a variable opens a confirmation modal from where you can decide to delete the variable or cancel.

Troubleshooting

A job shows an empty value. The AI couldn’t find the requested information in that job’s description, or the ATS field is empty. Check the JD / ATS record, tighten the prompt, or fill the value manually on the job’s settings page. I edited the prompt but old jobs still show the old value. A prompt edit triggers a background re-extraction. Wait a few minutes and refresh. If it still hasn’t updated for a specific job, click Autofill on that field from the job settings page. The ATS field variable renders as empty. Confirm the ATS Object and ATS Field match your ATS exactly (field API names are case-sensitive). A typo fails silently and returns an empty string.