diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
index 5a00b3e790..d1659e51d1 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/FlowItem.svelte
@@ -92,7 +92,7 @@
     )
     loopBlock.blockToLoop = block.id
     block.loopBlock = loopBlock.id
-    automationStore.actions.addBlockToAutomation(loopBlock, blockIdx - 1)
+    automationStore.actions.addBlockToAutomation(loopBlock, blockIdx)
     await automationStore.actions.save(
       $automationStore.selectedAutomation?.automation
     )
@@ -131,16 +131,6 @@
         </div>
 
         <div class="blockTitle">
-          {#if testResult && testResult[0]}
-            <div style="float: right;" on:click={() => resultsModal.show()}>
-              <StatusLight
-                positive={isTrigger || testResult[0].outputs?.success}
-                negative={!testResult[0].outputs?.success}
-                ><Body size="XS">View response</Body></StatusLight
-              >
-            </div>
-          {/if}
-
           <div
             style="margin-left: 10px;"
             on:click={() => {
diff --git a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte
index 7dfdff20a7..67c7f493e8 100644
--- a/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte
+++ b/packages/builder/src/components/automation/AutomationBuilder/FlowChart/ResultsModal.svelte
@@ -1,5 +1,5 @@
 <script>
-  import { ModalContent, Icon, Detail, TextArea } from "@budibase/bbui"
+  import { ModalContent, Icon, Detail, TextArea, Label } from "@budibase/bbui"
 
   export let testResult
   export let isTrigger
@@ -10,7 +10,7 @@
 <ModalContent
   showCloseIcon={false}
   showConfirmButton={false}
-  title="Test Automation"
+  title="Test Results"
   cancelText="Close"
 >
   <div slot="header">
@@ -26,7 +26,18 @@
       {/if}
     </div>
   </div>
-
+  <span>
+    {#if testResult[0].outputs.iterations}
+      <div style="display: flex;">
+        <Icon name="Reuse" />
+        <div style="margin-left: 10px;">
+          <Label>
+            This loop ran {testResult[0].outputs.iterations} times.</Label
+          >
+        </div>
+      </div>
+    {/if}
+  </span>
   <div
     on:click={() => {
       inputToggled = !inputToggled
diff --git a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
index b87d08a5ab..ae5fc3d0df 100644
--- a/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
+++ b/packages/builder/src/components/automation/SetupPanel/AutomationBlockSetup.svelte
@@ -30,6 +30,7 @@
   import FilterDrawer from "components/design/PropertiesPanel/PropertyControls/FilterEditor/FilterDrawer.svelte"
   import { LuceneUtils } from "@budibase/frontend-core"
   import { getSchemaForTable } from "builderStore/dataBinding"
+  import { cloneDeep } from "lodash/fp"
 
   export let block
   export let testData
@@ -88,34 +89,61 @@
     if (!block || !automation) {
       return []
     }
-
     // Find previous steps to the selected one
     let allSteps = [...automation.steps]
+
     if (automation.trigger) {
       allSteps = [automation.trigger, ...allSteps]
     }
-    const blockIdx = allSteps.findIndex(step => step.id === block.id)
+    let blockIdx = allSteps.findIndex(step => step.id === block.id)
 
-    // Extract all outputs from all previous steps as available bindings
+    let loopBlockIdx = cloneDeep(allSteps)
+      .splice(0, blockIdx)
+      .findIndex(x => x.stepId === "LOOP")
+    // if a loop stepId exists in previous steps, we need to decerement the blockIdx
+    if (loopBlockIdx > -1 && blockIdx > loopBlockIdx) {
+      blockIdx--
+    }
+    // Extract all outputs from all previous steps as available bindins
     let bindings = []
     for (let idx = 0; idx < blockIdx; idx++) {
-      const outputs = Object.entries(
-        allSteps[idx].schema?.outputs?.properties ?? {}
-      )
+      let isLoopBlock = allSteps[idx + 1]?.blockToLoop === block.id
+
+      let schema = allSteps[idx]?.schema?.outputs?.properties ?? {}
+      if (isLoopBlock) {
+        schema = {
+          currentItem: {
+            type: "string",
+            description: "the item currently being executed",
+          },
+        }
+      }
+
+      if (loopBlockIdx && allSteps[blockIdx - 1]?.stepId === "LOOP") {
+        schema = {
+          ...schema,
+          ...$automationStore.blockDefinitions.ACTION.LOOP.schema.outputs
+            .properties.properties,
+        }
+      }
+      const outputs = Object.entries(schema)
+
       bindings = bindings.concat(
         outputs.map(([name, value]) => {
-          let runtimeName =
-            $automationStore.selectedAutomation.automation.definition.steps.find(
-              x => block.id === x.blockToLoop
-            )
-              ? `loop.${name}`
-              : `steps.${idx}.${name}`
+          let runtimeName = isLoopBlock
+            ? `loop.${name}`
+            : `steps.${idx}.${name}`
           const runtime = idx === 0 ? `trigger.${name}` : runtimeName
           return {
             label: runtime,
             type: value.type,
             description: value.description,
-            category: idx === 0 ? "Trigger outputs" : `Step ${idx} outputs`,
+            category:
+              idx === 0
+                ? "Trigger outputs"
+                : isLoopBlock
+                ? "Loop Outputs"
+                : `Step ${idx} outputs`,
             path: runtime,
           }
         })
diff --git a/packages/server/src/automations/steps/loop.js b/packages/server/src/automations/steps/loop.js
index 543317f3be..14c58aee6a 100644
--- a/packages/server/src/automations/steps/loop.js
+++ b/packages/server/src/automations/steps/loop.js
@@ -48,8 +48,3 @@ exports.definition = {
   },
   type: "LOGIC",
 }
-
-exports.run = async function filter({ inputs }) {
-  let currentItem = inputs.binding
-  return { currentItem }
-}
diff --git a/packages/server/src/threads/automation.js b/packages/server/src/threads/automation.js
index 6669f529a3..8297b5ab12 100644
--- a/packages/server/src/threads/automation.js
+++ b/packages/server/src/threads/automation.js
@@ -86,26 +86,149 @@ class Orchestrator {
     let stepCount = 0
     let loopStepNumber
     let loopSteps = []
-    let lastLoopStep
     for (let step of automation.definition.steps) {
       stepCount++
+      let input
       if (step.stepId === LOOP_STEP_ID) {
         loopStep = step
         loopStepNumber = stepCount
         continue
       }
-      let iterations = loopStep ? loopStep.inputs.binding.split(",").length : 1
 
+      if (loopStep) {
+        input = await processObject(loopStep.inputs, this._context)
+      }
+      let iterations = loopStep ? input.binding.length : 1
+      let iterationCount = 0
       for (let index = 0; index < iterations; index++) {
         let originalStepInput = cloneDeep(step.inputs)
 
-        /*
-        if (step.stepId === LOOP_STEP_ID && index >= loopStep.inputs.iterations) {
-          this.executionOutput.steps[loopStepNumber].outputs.status = "Loop Broken"
-          break
+        // Handle if the user has set a max iteration count or if it reaches the max limit set by us
+        if (loopStep) {
+          // lets first of all handle the input
+          // if the input is array then use it, if it is a string then split it on every new line
+          let newInput = await processObject(
+            loopStep.inputs,
+            cloneDeep(this._context)
+          )
+          newInput = automationUtils.cleanInputValues(
+            newInput,
+            loopStep.schema.inputs
+          )
+          this._context.steps[loopStepNumber] = {
+            currentItem: newInput.binding[index],
+          }
+          let tempOutput = { items: loopSteps, iterations: iterationCount }
+
+          if (
+            loopStep.inputs.option === "Array" &&
+            !Array.isArray(newInput.binding)
+          ) {
+            this.executionOutput.steps.splice(loopStepNumber, 0, {
+              id: step.id,
+              stepId: step.stepId,
+              outputs: {
+                ...tempOutput,
+                success: true,
+                status: "INCORRECT_TYPE",
+              },
+              inputs: step.inputs,
+            })
+            this._context.steps.splice(loopStepNumber, 0, {
+              ...tempOutput,
+              success: true,
+              status: "INCORRECT_TYPE",
+            })
+
+            loopSteps = null
+            loopStep = null
+            break
+          } else if (
+            loopStep.inputs.option === "String" &&
+            typeof newInput.binding !== "string"
+          ) {
+            this.executionOutput.steps.splice(loopStepNumber, 0, {
+              id: step.id,
+              stepId: step.stepId,
+              outputs: {
+                ...tempOutput,
+                success: false,
+                status: "INCORRECT_TYPE",
+              },
+              inputs: step.inputs,
+            })
+            this._context.steps.splice(loopStepNumber, 0, {
+              ...tempOutput,
+              success: true,
+              status: "INCORRECT_TYPE",
+            })
+
+            loopSteps = null
+            loopStep = null
+            break
+          }
+
+          // The "Loop" binding in the front end is "fake", so replace it here so the context can understand it
+          for (let key in originalStepInput) {
+            if (key === "row") {
+              for (let test in originalStepInput["row"]) {
+                originalStepInput["row"][test] = originalStepInput["row"][
+                  test
+                ].replace(/loop/, `steps.${loopStepNumber}`)
+              }
+            } else {
+              originalStepInput[key] = originalStepInput[key].replace(
+                /loop/,
+                `steps.${loopStepNumber}`
+              )
+            }
+          }
+
+          if (index >= loopStep.inputs.iterations) {
+            this.executionOutput.steps.splice(loopStepNumber, 0, {
+              id: step.id,
+              stepId: step.stepId,
+              outputs: { ...tempOutput, success: true, status: "LOOP_BROKEN" },
+              inputs: step.inputs,
+            })
+            this._context.steps.splice(loopStepNumber, 0, {
+              ...tempOutput,
+              success: true,
+              status: "LOOP_BROKEN",
+            })
+
+            loopSteps = null
+            loopStep = null
+            break
+          }
+
+          if (
+            this._context.steps[loopStepNumber]?.currentItem ===
+            loopStep.inputs.failure
+          ) {
+            console.log("hello?????")
+            this.executionOutput.steps.splice(loopStepNumber, 0, {
+              id: step.id,
+              stepId: step.stepId,
+              outputs: {
+                ...tempOutput,
+                success: false,
+                status: "FAILURE_CONDITION_MET",
+              },
+              inputs: step.inputs,
+            })
+            this._context.steps.splice(loopStepNumber, 0, {
+              ...tempOutput,
+              success: false,
+              status: "FAILURE_CONDITION_MET",
+            })
+
+            loopSteps = null
+            loopStep = null
+            break
+          }
         }
-        
-        */
+
         // execution stopped, record state for that
         if (stopped) {
           this.updateExecutionOutput(step.id, step.stepId, {}, STOPPED_STATUS)
@@ -113,11 +236,6 @@ class Orchestrator {
         }
 
         // If it's a loop step, we need to manually add the bindings to the context
-        if (loopStep) {
-          this._context.steps[loopStepNumber] = {
-            currentItem: loopStep.inputs.binding.split(",")[index],
-          }
-        }
         let stepFn = await this.getStepFunctionality(step.stepId)
         let inputs = await processObject(originalStepInput, this._context)
         inputs = automationUtils.cleanInputValues(inputs, step.schema.inputs)
@@ -143,7 +261,6 @@ class Orchestrator {
             })
             continue
           }
-          this._context.steps.splice(loopStepNumber, 1)
           if (loopStep && loopSteps) {
             loopSteps.push(outputs)
           } else {
@@ -158,26 +275,34 @@ class Orchestrator {
           console.error(`Automation error - ${step.stepId} - ${err}`)
           return err
         }
-
-        if (index === iterations - 1) {
-          lastLoopStep = loopStep
-          loopStep = null
-          break
+        if (loopStep) {
+          iterationCount++
+          if (index === iterations - 1) {
+            loopStep = null
+            this._context.steps.splice(loopStepNumber, 1)
+            break
+          }
         }
       }
 
       if (loopSteps && loopSteps.length) {
-        let tempOutput = { success: true, outputs: loopSteps }
-        this.executionOutput.steps.splice(loopStep, 0, {
-          id: lastLoopStep.id,
-          stepId: lastLoopStep.stepId,
+        let tempOutput = {
+          success: true,
+          items: loopSteps,
+          iterations: iterationCount,
+        }
+        this.executionOutput.steps.splice(loopStepNumber + 1, 0, {
+          id: step.id,
+          stepId: step.stepId,
           outputs: tempOutput,
           inputs: step.inputs,
         })
-        this._context.steps.splice(loopStep, 0, tempOutput)
+
+        this._context.steps.splice(loopStepNumber, 0, tempOutput)
         loopSteps = null
       }
     }
+
     return this.executionOutput
   }
 }