Skip to content

9.3 Custom Code Examples

You know how to add Custom Code columns and write basic scripts. Now let's explore real-world examples you can adapt for your automations. Each example shows the business problem, the solution, and how to implement it.


Example 1: Lead Scoring Algorithm

The Business Problem

Challenge: You need to score leads based on multiple factors—company size, industry, engagement, contact role, and more. Each factor has different weight.

Manual approach: Would require spreadsheet with complex formulas, or manual review

Custom code solution: Automated scoring that adapts to your criteria


The Setup

Create these columns first:

Column NameTypeDescription
EmailTextContact email
Contact RoleTextJob title
Email OpensNumberEmail open count
Link ClicksNumberLink click count
Company Data(From enrichment)Company information
Lead ScoreCustom CodeThis is what we're building

The Code

When adding the Lead Score column:

  1. Click + Add Column

  2. Choose Custom Code column type

  3. Enter configuration:

    • Column name: lead_score
    • Display label: "Lead Score"
    • Output type: Map<String, Object>
  4. Write your code:

groovy
// Custom lead scoring based on multiple factors
let score = 0

// Factor 1: Company size score
let companySize = [Company Size] || 0
if (companySize > 1000) {
  score += 30
} else if (companySize > 100) {
  score += 20
} else if (companySize > 10) {
  score += 10
}

// Factor 2: Industry score
let industry = [Industry]
let targetIndustries = ['Technology', 'Finance', 'Healthcare']
if (targetIndustries.includes(industry)) {
  score += 25
}

// Factor 3: Engagement score
let emailOpens = [Email Opens] || 0
let linkClicks = [Link Clicks] || 0
score += emailOpens * 2
score += linkClicks * 5

// Factor 4: Role score
let role = [Contact Role]
if (role && (role.includes('Director') || role.includes('VP'))) {
  score += 20
}
if (role && (role.includes('C-level') || role.includes('CEO'))) {
  score += 30
}

// Factor 5: Email domain score (educational institutions)
let email = [Email]
if (email && email.endsWith('.edu')) {
  score += 15
}

// Return structured result
return {
  total_score: score,
  grade: score > 70 ? 'A' : score > 50 ? 'B' : score > 30 ? 'C' : 'D',
  qualified: score > 50
}

How It Works

Input: Multiple data points about the lead

Processing:

  1. Company size (0-30 points): Larger companies score higher
  2. Industry (0-25 points): Target industries get bonus
  3. Engagement (0-∞ points): More interaction = higher score
  4. Role (0-30 points): Decision-makers score higher
  5. Email domain (0-15 points): Educational institutions get bonus

Output: Object with three fields:

  • total_score: Numeric score (0-100+)
  • grade: Letter grade (A/B/C/D)
  • qualified: Boolean (true if score > 50)

Lead Scoring Results

Custom code calculates scores based on multiple factors

EmailRoleCompanyIndustryScoreGrade
john@bigtech.comVP Engineering1500 employeesTechnology85A
sarah@startup.ioDeveloper25 employeesTechnology45C
mike@hospital.eduCTO800 employeesHealthcare75B
jane@retail.comManager50 employeesRetail25D

Scoring Factors:

  • ✅ Company Size: 0-30 points
  • ✅ Industry Match: 0-25 points
  • ✅ Decision Maker Role: 0-30 points
  • ✅ Email Domain: 0-15 points

Using the Results

In another column (e.g., filter qualified leads):

Create a new column and reference the Lead Score:

groovy
let scoring = [Lead Score]
let isQualified = scoring.qualified || false

if (isQualified) {
  return "ROUTE TO SALES"
} else {
  return "ROUTE TO NURTURE"
}

Or as a condition on other columns:

  • Open the column's Run Configuration
  • Add a condition: "Only run if lead is qualified"
  • The system checks Lead Score.qualified == true

Customizing for Your Business

Change target industries:

Find this line in the code:

groovy
let targetIndustries = ['Technology', 'Finance', 'Healthcare']

Replace with your industries:

groovy
let targetIndustries = ['Manufacturing', 'Retail', 'Logistics']

Adjust scoring weights:

Give more weight to engagement:

groovy
score += emailOpens * 5  // Changed from 2
score += linkClicks * 10 // Changed from 5

Add new factors:

groovy
// Factor 6: Geographic score
let country = [Country]
if (country === 'United States') {
  score += 20
}

Example 2: Data Cleaning and Standardization

The Business Problem

Challenge: Phone numbers come in various formats—some with country codes, some with dashes, some with parentheses. You need consistent format for CRM integration.

Examples of messy data:

  • (555) 123-4567
  • 555-123-4567
  • 5551234567
  • +1 555 123 4567
  • 1-555-123-4567

Need: All formatted as +1 (555) 123-4567


The Setup

Create these columns:

Column NameTypeDescription
Raw PhoneTextPhone number as entered
Standardized PhoneCustom CodeCleaned format

The Code

When adding Standardized Phone column:

  1. Add Custom Code column

  2. Configuration:

    • Column name: standardized_phone
    • Display label: "Phone Number"
    • Output type: String
  3. Write code:

groovy
// Standardize phone numbers
let phone = [Raw Phone]

// Return null if no phone
if (!phone) return null

// Remove all non-numeric characters
phone = phone.replace(/[^\d]/g, '')

// Format based on length
if (phone.length === 10) {
  // US format (no country code)
  return `+1 (${phone.slice(0,3)}) ${phone.slice(3,6)}-${phone.slice(6)}`
} else if (phone.length === 11 && phone[0] === '1') {
  // US with leading 1
  return `+${phone[0]} (${phone.slice(1,4)}) ${phone.slice(4,7)}-${phone.slice(7)}`
} else if (phone.length > 11) {
  // International (keep as is with + prefix)
  return `+${phone}`
} else {
  // Invalid length - return cleaned but not formatted
  return phone
}

How It Works

Step 1: Remove all non-numeric characters

  • (555) 123-45675551234567
  • +1-555-123-456715551234567

Step 2: Identify format based on length

  • 10 digits: US number without country code
  • 11 digits starting with 1: US number with country code
  • Other: International format

Step 3: Apply formatting

  • US: +1 (555) 123-4567
  • International: + followed by digits

Phone Number Standardization

Custom code converts messy formats to consistent standard

Before
(555) 123-4567
After
+1 (555) 123-4567
Before
555-123-4567
After
+1 (555) 123-4567
Before
5551234567
After
+1 (555) 123-4567
Before
+1 555 123 4567
After
+1 (555) 123-4567
Before
1-555-123-4567
After
+1 (555) 123-4567

What the code does:

  1. Removes all non-numeric characters
  2. Detects format based on digit count
  3. Applies US phone number formatting
  4. Adds country code (+1)

Testing

Test data to add:

Raw PhoneExpected Result
(555) 123-4567+1 (555) 123-4567
5551234567+1 (555) 123-4567
+1 555-123-4567+1 (555) 123-4567
442012345678+442012345678

Add these rows and verify all formats convert correctly!


Variations

For other countries (e.g., UK):

groovy
let phone = [Raw Phone]
if (!phone) return null

phone = phone.replace(/[^\d]/g, '')

if (phone.length === 10 && !phone.startsWith('44')) {
  // UK number without country code
  return `+44 ${phone.slice(0,4)} ${phone.slice(4,7)} ${phone.slice(7)}`
} else if (phone.length === 12 && phone.startsWith('44')) {
  // UK with country code
  return `+${phone.slice(0,2)} ${phone.slice(2,6)} ${phone.slice(6,9)} ${phone.slice(9)}`
} else {
  return `+${phone}`
}

For email standardization:

groovy
let email = [Raw Email]
if (!email) return null

// Convert to lowercase
email = email.toLowerCase().trim()

// Validate format
if (!email.includes('@') || !email.includes('.')) {
  return null // Invalid email
}

return email

Example 3: Smart Caching with Conditional Processing

The Business Problem

Challenge: API enrichment is expensive ($1 per call). You don't want to call API every time—only when data is stale or missing.

Solution: Cache results, only refresh if older than 7 days

Savings: 90% reduction in API calls (refresh weekly vs. daily)


The Setup

Create these columns:

Column NameTypeDescription
EmailTextEmail to enrich
Cached Enrichment(Previous enrichment)Previous result
Smart EnrichmentCustom CodeSmart caching logic

The Code

When adding Smart Enrichment column:

  1. Add Custom Code column

  2. Configuration:

    • Column name: smart_enrichment
    • Display label: "Enrichment (Cached)"
    • Output type: Map<String, Object>
  3. Write code:

groovy
let email = [Email]
let existingData = [Cached Enrichment]

// Check if cached data exists and is recent
if (existingData && existingData.cached_at) {
  try {
    // Calculate cache age in days
    let cachedDate = new Date(existingData.cached_at)
    let currentDate = new Date()
    let cacheAge = (currentDate - cachedDate) / (1000 * 60 * 60 * 24)

    // If cache is less than 7 days old, return it
    if (cacheAge < 7) {
      return {
        from_cache: true,
        cache_age_days: Math.round(cacheAge * 10) / 10,
        data: existingData
      }
    }
  } catch (e) {
    // If date parsing fails, proceed to fetch fresh data
  }
}

// No cache or cache is stale
// In real implementation, this would trigger your enrichment column
return {
  from_cache: false,
  needs_refresh: true,
  email: email,
  message: 'Cache miss - fresh data needed'
}

How It Works

Decision tree:

Is there cached data?
├─ NO → Fetch fresh (call API)
└─ YES → Is cache < 7 days old?
    ├─ YES → Return cached (save $1)
    └─ NO → Fetch fresh (call API)

Cache hit (within 7 days):

  • Returns existing data
  • Sets from_cache: true
  • Shows cache age

Cache miss (> 7 days or no cache):

  • Returns marker
  • Would trigger API call (in real implementation)
  • Updates cache

Smart Caching in Action

Only refreshes data older than 7 days

EmailLast EnrichedStatusCost
john@example.com2 days agoUsing Cache$0
sarah@example.com5 days agoUsing Cache$0
mike@example.com8 days agoRefreshing$1
jane@example.comNeverNew Call$1

❌ Without Caching

$30,000

30,000 API calls per month

✅ With Caching

$4,300

4,300 API calls per month (86% savings!)


Cost Savings

Without caching:

  • 1,000 leads
  • Run daily for 30 days
  • 30,000 API calls
  • Cost: $30,000

With caching (7-day refresh):

  • Initial: 1,000 API calls
  • Weekly refresh: ~143 calls per day (1000 ÷ 7)
  • Monthly: ~4,300 calls
  • Cost: $4,300
  • Savings: $25,700 (86%)

Example 4: Data Aggregation and Reporting

The Business Problem

Challenge: Calculate summary statistics from multiple columns—total orders, average order value, conversion rate.

Manual approach: Export to Excel, create pivot table

Custom code solution: Real-time calculation in taible


The Setup

Create these columns:

Column NameTypeDescription
Orders(Collection of orders)Array of orders
Leads(Collection of leads)Array of leads
Summary StatsCustom CodeAggregated statistics

The Code

groovy
// Get data
let orders = [Orders] || []
let leads = [Leads] || []

// Calculate order statistics
let totalOrders = orders.length
let totalRevenue = orders.reduce((sum, order) => sum + (order.amount || 0), 0)
let avgOrderValue = totalOrders > 0 ? totalRevenue / totalOrders : 0

// Calculate lead statistics
let totalLeads = leads.length
let qualifiedLeads = leads.filter(lead => lead.qualified === true).length
let conversionRate = totalLeads > 0 ? (totalOrders / totalLeads) * 100 : 0

// Find top order
let topOrder = orders.reduce((max, order) =>
  (order.amount || 0) > (max.amount || 0) ? order : max
, {})
let topOrderAmount = topOrder.amount || 0

// Calculate time-based metrics
let now = new Date()
let ordersThisMonth = orders.filter(order => {
  if (!order.date) return false
  let orderDate = new Date(order.date)
  return orderDate.getMonth() === now.getMonth() &&
         orderDate.getFullYear() === now.getFullYear()
}).length

// Return comprehensive summary
return {
  // Order metrics
  total_orders: totalOrders,
  total_revenue: Math.round(totalRevenue * 100) / 100,
  avg_order_value: Math.round(avgOrderValue * 100) / 100,
  top_order_amount: topOrderAmount,
  orders_this_month: ordersThisMonth,

  // Lead metrics
  total_leads: totalLeads,
  qualified_leads: qualifiedLeads,
  qualification_rate: Math.round((qualifiedLeads / totalLeads) * 1000) / 10,

  // Performance metrics
  conversion_rate: Math.round(conversionRate * 100) / 100,

  // Summary
  status: totalOrders > 0 ? 'ACTIVE' : 'NO_ORDERS',
  performance: conversionRate > 5 ? 'GOOD' : conversionRate > 2 ? 'AVERAGE' : 'NEEDS_IMPROVEMENT'
}

Output Example

The cell will display a structured object:

Real-Time Summary Statistics

Custom code calculates metrics from multiple columns

Total Orders
47
Total Revenue
$28,450.75
Avg Order Value
$605.33
Orders This Month
12
Total Leads
850
Qualified Leads
340
Conversion Rate
5.53%
ACTIVE
Performance: GOOD

Using in Other Columns

Access individual metrics in another column:

groovy
let stats = [Summary Stats]
let revenue = stats.total_revenue || 0
let conversionRate = stats.conversion_rate || 0

return `Revenue: $${revenue}, Conversion: ${conversionRate}%`

Or display formatted in a dashboard


Common Code Patterns

Pattern 1: Safe Data Access

Always use fallback values to prevent errors:

groovy
let value = [Column Name] || 'default'
let number = [Number Column] || 0
let array = [List Column] || []

Pattern 2: Conditional Return

Exit early if required data is missing:

groovy
if (!requiredField) return null
// ... rest of code only runs if field exists

Pattern 3: Error Handling

Wrap risky operations:

groovy
try {
  let result = riskyOperation()
  return result
} catch (e) {
  return { error: true, message: e.message }
}

Pattern 4: Calculate and Format

Round numbers for display:

groovy
let total = items.reduce((sum, item) => sum + item.amount, 0)
return Math.round(total * 100) / 100 // 2 decimal places

Pattern 5: Filter and Transform Collections

Process arrays:

groovy
let filtered = items.filter(item => item.status === 'active')
let names = filtered.map(item => item.name)
return names

Viewing Your Code Results

In the Cell

When a Custom Code column executes successfully, you'll see:

Custom Code Column Configuration

Write your own logic to process data

Access column data, write custom logic, and return results

  • A green checkmark badge with the result
  • Click the cell to expand and see the full object structure
  • If it returns an object, you'll see a structured view

In the Sidebar

Click any Custom Code cell to open the sidebar and see:

  • Full JSON structure of the result
  • All nested properties and values
  • Copy values for use elsewhere

Summary: Custom Code Examples

You now have real-world examples:

Lead Scoring: Multi-factor scoring algorithm with grades

Data Cleaning: Phone number standardization with format detection

Smart Caching: Conditional processing to save API costs

Data Aggregation: Calculate summary statistics from collections

Next steps:

  1. Choose an example that fits your use case
  2. Adapt the code to your column names
  3. Test with sample data
  4. Customize logic for your business rules

Next Steps

You've completed Chapter 9: Custom Code Columns! You can now:

✅ Understand when to use custom code ✅ Add Custom Code columns via UI ✅ Write scripts for automation ✅ Implement real-world examples ✅ Access data, handle errors, and optimize performance

Next chapter will explore additional advanced features and best practices for building complex automations.

Let's continue building! 🚀

Built with VitePress