Custom Script Fields

Custom Script Fields let you create your own computed fields with arbitrary JavaScript logic. Unlike built-in script fields (which offer pre-made templates), custom script fields give you full control over what to calculate and how to display it.

Creating a Custom Script Field

  1. Go to Apps → ScriptForge → Scripted Fields
  2. Click Create Custom Field
  3. Fill in:
    • Field Name — shown as the field label on issues
    • Field Type — String, Number, or Paragraph
    • Script — your computation logic
  4. Save and add the field to your screens

Field Type Details

String Fields

Return a single string value. Displayed as a text label.

// Show which sprint the issue is overdue in
const issue = await WorkItems.getByKey(context.issueKey);
const dueDate = issue.dueDate ? new Date(issue.dueDate) : null;

if (!dueDate) return 'No due date';
if (dueDate < new Date()) return '⚠️ Overdue';
return 'On track';

Number Fields

Return a numeric value. Can be used in Jira's built-in sum/average gadgets.

// Total story points of all sub-tasks
const issue = await WorkItems.getByKey(context.issueKey);
const subtasks = await issue.getSubTaskObjects();

let total = 0;
for (const task of subtasks) {
  const points = task.getCustomFieldValue('customfield_10016') || 0;
  total += points;
}
return total;

Paragraph Fields

Return multi-line text. Useful for summaries or formatted data.

// List all comments authors (last 5)
const issue = await WorkItems.getByKey(context.issueKey);
const comments = await issue.getComments();
const recent = comments.slice(-5);

return recent.map(c => `${c.author.displayName} - ${c.created}`).join('\n');

Using HAPI in Script Fields

Script fields have full access to the HAPI library:

// Check if the assignee is in the "developers" group
const issue = await WorkItems.getByKey(context.issueKey);
const assigneeId = issue.assignee;

if (!assigneeId) return 'Unassigned';

const user = await Users.getByAccountId(assigneeId);
const groups = await user.getGroups();
const isDev = groups.some(g => g.name === 'developers');

return isDev ? 'Developer' : 'Non-developer';

Using Entity Properties

For expensive calculations, consider writing the result via a listener and reading it in the scripted field:

// Read a pre-computed value from entity properties
const issue = await WorkItems.getByKey(context.issueKey);
const props = await issue.getEntityProperties();
const score = await props.getInteger('risk-score');

return score || 0;

Tips

  • Keep scripts fast — they run on every issue render
  • Use entity properties to cache expensive calculations (computed by listeners/jobs)
  • Return null or an empty string if there's nothing to display
  • Number fields should always return a numeric value (or 0), not text