Documentation>Automation Workflows
Advanced LevelPremium Feature

Automation Workflows

Create complex automation sequences with conditional logic, multi-step processes, and intelligent decision trees for advanced campaign management.

45 minutes
Advanced Workflow Capabilities

Intelligent Decision Making

  • Multi-condition branching logic
  • Time-based automation triggers
  • Performance threshold automation
  • Cross-campaign coordination

Advanced Orchestration

  • Sequential workflow execution
  • Parallel task processing
  • Error recovery mechanisms
  • State persistence and resume
Decision Trees
  • Complex branching logic
  • Nested condition evaluation
  • Dynamic path selection
  • Fallback strategies
Event Triggers
  • Performance thresholds
  • Time-based scheduling
  • External API events
  • Data change detection
State Management
  • Workflow persistence
  • Progress tracking
  • Resume capabilities
  • Audit trails
Advanced Workflow Example: Smart Campaign Lifecycle Management
// Advanced workflow: Intelligent campaign lifecycle automation
class CampaignLifecycleWorkflow {
  constructor() {
    this.workflowState = this.loadWorkflowState();
    this.decisionTree = this.buildDecisionTree();
  }
  
  execute() {
    Logger.log("=== Smart Campaign Lifecycle Workflow ===");
    
    const campaigns = this.getCampaignsForEvaluation();
    
    campaigns.forEach(campaign => {
      const context = this.buildCampaignContext(campaign);
      const decision = this.evaluateDecisionTree(context);
      
      Logger.log(`${campaign.getName()}: Stage=${context.stage}, Decision=${decision.action}`);
      
      this.executeAction(campaign, decision, context);
      this.updateWorkflowState(campaign, decision);
    });
    
    this.saveWorkflowState();
    this.generateWorkflowReport();
  }
  
  buildCampaignContext(campaign) {
    const stats30 = campaign.getStatsFor('LAST_30_DAYS');
    const stats7 = campaign.getStatsFor('LAST_7_DAYS');
    const createdDate = new Date(campaign.getCreatedDate());
    const campaignAge = (Date.now() - createdDate.getTime()) / (1000 * 60 * 60 * 24);
    
    return {
      campaign: campaign,
      age: campaignAge,
      stage: this.determineCampaignStage(campaignAge, stats30),
      performance: {
        roas30: stats30.getConversionValue() / Math.max(stats30.getCost(), 1),
        roas7: stats7.getConversionValue() / Math.max(stats7.getCost(), 1),
        clicks30: stats30.getClicks(),
        conversions30: stats30.getConversions(),
        ctr: stats30.getCtr(),
        avgCpc: stats30.getAverageCpc()
      },
      budget: {
        current: campaign.getBudget(),
        utilization: stats7.getCost() / (campaign.getBudget() * 7),
        recommended: this.calculateOptimalBudget(stats30)
      },
      trends: this.analyzeTrends(campaign),
      competitivePosition: this.getCompetitiveData(campaign)
    };
  }
  
  buildDecisionTree() {
    return {
      // Learning Phase (0-14 days)
      learning: {
        conditions: [
          {
            if: ctx => ctx.age <= 14,
            then: this.learningPhaseDecisions()
          }
        ]
      },
      
      // Growth Phase (15-45 days)
      growth: {
        conditions: [
          {
            if: ctx => ctx.age > 14 && ctx.age <= 45,
            then: this.growthPhaseDecisions()
          }
        ]
      },
      
      // Maturity Phase (45+ days)
      maturity: {
        conditions: [
          {
            if: ctx => ctx.age > 45,
            then: this.maturityPhaseDecisions()
          }
        ]
      }
    };
  }
  
  learningPhaseDecisions() {
    return [
      {
        if: ctx => ctx.performance.clicks30 < 100,
        action: 'increase_budget',
        params: { multiplier: 1.5, reason: 'Insufficient data volume' }
      },
      {
        if: ctx => ctx.performance.ctr < 0.02,
        action: 'optimize_ads',
        params: { focus: 'creative_testing', reason: 'Low CTR indicates poor ad relevance' }
      },
      {
        if: ctx => ctx.performance.clicks30 >= 100 && ctx.performance.conversions30 === 0,
        action: 'review_targeting',
        params: { focus: 'audience_refinement', reason: 'Clicks without conversions' }
      },
      {
        if: ctx => ctx.performance.roas30 > 3.0 && ctx.performance.conversions30 >= 5,
        action: 'graduate_to_growth',
        params: { reason: 'Strong early performance warrants scaling' }
      }
    ];
  }
  
  growthPhaseDecisions() {
    return [
      {
        if: ctx => ctx.performance.roas30 > 4.0 && ctx.budget.utilization > 0.8,
        action: 'aggressive_scale',
        params: { 
          budgetMultiplier: 2.0, 
          bidIncrease: 0.2,
          reason: 'High ROAS with full budget utilization'
        }
      },
      {
        if: ctx => ctx.performance.roas7 < ctx.performance.roas30 * 0.8,
        action: 'performance_decline_response',
        params: { 
          investigate: ['seasonality', 'competition', 'audience_saturation'],
          reason: 'Recent performance decline detected'
        }
      },
      {
        if: ctx => ctx.trends.declining && ctx.competitivePosition.pressure > 0.7,
        action: 'competitive_response',
        params: { 
          strategy: 'defensive_bidding',
          reason: 'High competitive pressure with declining trends'
        }
      }
    ];
  }
  
  maturityPhaseDecisions() {
    return [
      {
        if: ctx => ctx.performance.roas30 < 2.0,
        action: 'optimization_or_pause',
        params: { 
          threshold: 1.5,
          gracePeriod: 7,
          reason: 'Consistently poor ROAS in mature campaign'
        }
      },
      {
        if: ctx => ctx.trends.stable && ctx.performance.roas30 > 3.0,
        action: 'maintain_and_optimize',
        params: { 
          focus: 'efficiency_improvements',
          reason: 'Stable, profitable mature campaign'
        }
      },
      {
        if: ctx => ctx.trends.growth_opportunity,
        action: 'strategic_expansion',
        params: { 
          areas: ['new_keywords', 'audience_expansion', 'geo_expansion'],
          reason: 'Growth opportunity identified in mature campaign'
        }
      }
    ];
  }
  
  executeAction(campaign, decision, context) {
    Logger.log(`Executing: ${decision.action} for ${campaign.getName()}`);
    Logger.log(`Reason: ${decision.params.reason}`);
    
    switch (decision.action) {
      case 'increase_budget':
        this.increaseBudget(campaign, decision.params.multiplier);
        break;
        
      case 'aggressive_scale':
        this.aggressiveScale(campaign, decision.params);
        break;
        
      case 'optimize_ads':
        this.optimizeAds(campaign, decision.params);
        break;
        
      case 'competitive_response':
        this.competitiveResponse(campaign, decision.params);
        break;
        
      case 'optimization_or_pause':
        this.optimizationOrPause(campaign, decision.params, context);
        break;
        
      case 'maintain_and_optimize':
        this.maintainAndOptimize(campaign, decision.params);
        break;
        
      default:
        Logger.log(`Action not implemented: ${decision.action}`);
    }
    
    // Schedule follow-up evaluation
    this.scheduleFollowUp(campaign, decision);
  }
  
  increaseBudget(campaign, multiplier) {
    const currentBudget = campaign.getBudget();
    const newBudget = Math.round(currentBudget * multiplier);
    const maxBudget = 5000; // Safety limit
    
    const finalBudget = Math.min(newBudget, maxBudget);
    campaign.setBudget(finalBudget);
    
    Logger.log(`Budget increased: €${currentBudget} → €${finalBudget}`);
  }
  
  aggressiveScale(campaign, params) {
    // Budget scaling
    this.increaseBudget(campaign, params.budgetMultiplier);
    
    // Bid increases for top keywords
    const keywords = campaign.keywords()
      .withCondition('Status = ENABLED')
      .orderBy('ConversionValue DESC')
      .withLimit(20)
      .get();
    
    let keywordsOptimized = 0;
    while (keywords.hasNext()) {
      const keyword = keywords.next();
      const currentBid = keyword.getMaxCpc();
      const newBid = currentBid * (1 + params.bidIncrease);
      
      keyword.setMaxCpc(newBid);
      keywordsOptimized++;
    }
    
    Logger.log(`Aggressive scaling: ${keywordsOptimized} keywords optimized`);
  }
}

This advanced workflow demonstrates intelligent campaign lifecycle management with context-aware decision making, multi-stage optimization, and adaptive strategies.

🧠 Intelligent Features

  • • Context-aware decision making
  • • Multi-phase campaign lifecycle management
  • • Adaptive optimization strategies
  • • Competitive pressure analysis

⚡ Automation Benefits

  • • Reduces manual campaign management by 80%
  • • Responds to performance changes within hours
  • • Prevents budget waste through early detection
  • • Scales successful campaigns automatically
Workflow State Management
// Advanced state management for workflow persistence
class WorkflowStateManager {
  constructor() {
    this.stateKey = 'workflow_state_v2';
    this.maxStateAge = 30 * 24 * 60 * 60 * 1000; // 30 days
  }
  
  loadWorkflowState() {
    try {
      const stateJson = PropertiesService.getScriptProperties().getProperty(this.stateKey);
      
      if (!stateJson) {
        return this.createInitialState();
      }
      
      const state = JSON.parse(stateJson);
      
      // Validate state age and structure
      if (this.isStateValid(state)) {
        Logger.log(`Loaded workflow state with ${Object.keys(state.campaigns).length} campaigns`);
        return state;
      } else {
        Logger.log('Invalid or expired state, creating new state');
        return this.createInitialState();
      }
      
    } catch (error) {
      Logger.log(`Error loading state: ${error.message}`);
      return this.createInitialState();
    }
  }
  
  saveWorkflowState(state) {
    try {
      // Clean old entries before saving
      const cleanedState = this.cleanOldEntries(state);
      
      // Add metadata
      cleanedState.lastUpdated = Date.now();
      cleanedState.version = '2.0';
      
      const stateJson = JSON.stringify(cleanedState);
      
      // Check size limits (PropertiesService has 9KB limit per property)
      if (stateJson.length > 8000) {
        Logger.log('State too large, compressing...');
        const compressedState = this.compressState(cleanedState);
        PropertiesService.getScriptProperties().setProperty(this.stateKey, JSON.stringify(compressedState));
      } else {
        PropertiesService.getScriptProperties().setProperty(this.stateKey, stateJson);
      }
      
      Logger.log(`Workflow state saved (${stateJson.length} chars)`);
      
    } catch (error) {
      Logger.log(`Error saving state: ${error.message}`);
    }
  }
  
  updateCampaignState(campaignId, updates) {
    const state = this.loadWorkflowState();
    
    if (!state.campaigns[campaignId]) {
      state.campaigns[campaignId] = {
        created: Date.now(),
        stage: 'learning',
        actions: [],
        metrics: {}
      };
    }
    
    // Merge updates
    Object.assign(state.campaigns[campaignId], updates);
    
    // Add timestamp
    state.campaigns[campaignId].lastUpdated = Date.now();
    
    this.saveWorkflowState(state);
  }
  
  logWorkflowAction(campaignId, action, result) {
    const state = this.loadWorkflowState();
    
    if (!state.campaigns[campaignId]) {
      this.updateCampaignState(campaignId, {});
      return this.logWorkflowAction(campaignId, action, result);
    }
    
    const actionLog = {
      timestamp: Date.now(),
      action: action.action,
      params: action.params,
      result: result,
      success: result.success || false
    };
    
    if (!state.campaigns[campaignId].actions) {
      state.campaigns[campaignId].actions = [];
    }
    
    state.campaigns[campaignId].actions.push(actionLog);
    
    // Keep only last 50 actions per campaign
    if (state.campaigns[campaignId].actions.length > 50) {
      state.campaigns[campaignId].actions = state.campaigns[campaignId].actions.slice(-50);
    }
    
    this.saveWorkflowState(state);
  }
  
  getWorkflowHistory(campaignId, days = 30) {
    const state = this.loadWorkflowState();
    const campaign = state.campaigns[campaignId];
    
    if (!campaign || !campaign.actions) {
      return [];
    }
    
    const cutoffTime = Date.now() - (days * 24 * 60 * 60 * 1000);
    
    return campaign.actions.filter(action => action.timestamp > cutoffTime);
  }
  
  createInitialState() {
    return {
      version: '2.0',
      created: Date.now(),
      lastUpdated: Date.now(),
      campaigns: {},
      globalSettings: {
        maxCampaignAge: 90,
        minConversionsForOptimization: 5,
        roasThresholds: {
          excellent: 4.0,
          good: 3.0,
          acceptable: 2.0,
          poor: 1.5
        }
      }
    };
  }
  
  isStateValid(state) {
    if (!state || !state.version || !state.lastUpdated) {
      return false;
    }
    
    const age = Date.now() - state.lastUpdated;
    return age < this.maxStateAge;
  }
  
  compressState(state) {
    // Simple compression: remove old action logs and compress metrics
    const compressed = { ...state };
    
    Object.keys(compressed.campaigns).forEach(campaignId => {
      const campaign = compressed.campaigns[campaignId];
      
      // Keep only last 10 actions
      if (campaign.actions && campaign.actions.length > 10) {
        campaign.actions = campaign.actions.slice(-10);
      }
      
      // Compress metrics (keep only essential data)
      if (campaign.metrics) {
        campaign.metrics = {
          lastRoas: campaign.metrics.lastRoas,
          lastUpdate: campaign.metrics.lastUpdate
        };
      }
    });
    
    return compressed;
  }
}

🔄 State Management Benefits

  • • Workflow continuity across script executions
  • • Historical action tracking and audit trails
  • • Progressive optimization based on past performance
  • • Recovery and resume capabilities after failures
  • • Data-driven decision making with historical context
🎯 Workflow Best Practices

Design Principles

  • Start simple, add complexity gradually
  • Build in error handling and recovery
  • Log all decision points and actions
  • Test workflows in preview mode extensively

Implementation Tips

  • Use state management for complex workflows
  • Implement circuit breakers for safety
  • Monitor workflow performance metrics
  • Regular workflow optimization and updates