diff --git a/omniture.module b/omniture.module
index 0397168..5f5c265 100644
--- a/omniture.module
+++ b/omniture.module
@@ -49,6 +49,70 @@ function omniture_menu() {
 }
 
 /**
+ * Implements hook_theme().
+ */
+function omniture_theme($existing, $type, $theme, $path) {
+  return array(
+    'omniture_variables' => array(
+      'render element' => 'form',
+    ),
+  );
+}
+
+/**
+ * Implements hook_context_plugins().
+ */
+function omniture_context_plugins() {
+  $plugins = array();
+  $plugins['omniture_reaction_variables'] = array(
+    'handler' => array(
+      'path' => drupal_get_path('module', 'omniture') .'/plugins/context',
+      'file' => 'omniture_reaction_variables.inc',
+      'class' => 'omniture_reaction_variables',
+      'parent' => 'context_reaction',
+    ),
+  );
+  return $plugins;
+}
+
+/**
+ * Implements hook_context_registry().
+ */
+function omniture_context_registry() {
+  $reg = array(
+    'reactions' => array(
+      'omniture_vars' => array(
+        'title' => t('Omniture Variables'),
+        'plugin' => 'omniture_reaction_variables',
+      ),
+    ),
+  );
+  return $reg;
+}
+
+/**
+ * Implementation of hook_omniture_variables().
+ */
+function omniture_omniture_variables() {
+  $variables = array();
+
+  // Include variables set using the context module.
+  if (module_exists('context')) {
+    if ($plugin = context_get_plugin('reaction', 'omniture_vars')) {
+      $variables = $plugin->execute($variables);
+    }
+  }
+
+  // Include variables from the "custom variables" section of the settings form.
+  $settings_variables = variable_get('omniture_variables', array());
+  foreach ($settings_variables as $variable) {
+    $variables[$variable['name']] = $variable['value'];
+  }
+
+  return array('variables' => $variables);
+}
+
+/**
  * Implements hook_page_alter().
  */
 function omniture_page_alter(&$page) {
@@ -129,6 +193,9 @@ function omniture_page_alter(&$page) {
 function _omniture_format_variables(array $variables = array()) {
   $extra_variables = omniture_get_variables();
 
+  // Create context data to be used by token.
+  $context = !empty($variables) ? _omniture_get_token_context() : array();
+
   $variables_formatted = '';
   foreach ($variables as $key => $value) {
     if (is_array($value)) {
@@ -141,7 +208,11 @@ function _omniture_format_variables(array $variables = array()) {
     }
 
     $key = check_plain($key);
-    $value = check_plain($value);
+    $value = token_replace($value, $context, array(
+      'clear' => TRUE,
+      'sanitize' => TRUE,
+    ));
+
     $variables_formatted .= "{$key}=\"{$value}\";\n";
   }
   return $variables_formatted;
@@ -150,7 +221,7 @@ function _omniture_format_variables(array $variables = array()) {
 /**
  * Menu callback; Omniture settings.
  */
-function omniture_admin_settings() {
+function omniture_admin_settings($form, &$form_state) {
   $form['general'] = array(
     '#type' => 'fieldset',
     '#title' => t('General settings'),
@@ -201,6 +272,21 @@ function omniture_admin_settings() {
     );
   }
 
+  $form['variables'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Custom Variables'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
+    '#description' => t('You can define tracking variables here. '),
+    '#weight' => '-3',
+  );
+  if (module_exists('token')) {
+    $form['variables']['#description'] .= t('You can use the table below to insert tokens as varible values.');
+  }
+
+  $existing_variables = isset($form_state['input']['omniture_variables']) ? $form_state['input']['omniture_variables'] : variable_get('omniture_variables', array());
+  _omniture_variables_form($form['variables'], $existing_variables);
+
   $form['advanced'] = array(
     '#type' => 'fieldset',
     '#title' => t('Advanced'),
@@ -222,6 +308,131 @@ function omniture_admin_settings() {
 }
 
 /**
+ * Helper form builder for a variables form.
+ */
+function _omniture_variables_form(&$form, $existing_variables = array()) {
+  $form['omniture_variables'] = array(
+    '#type' => 'markup',
+    '#tree' => FALSE,
+    '#prefix' => '<div id="omniture-variables-wrapper">',
+    '#suffix' => '</div>',
+    '#theme' => 'omniture_variables',
+    '#element_validate' => array('omniture_variables_form_validate'),
+  );
+  // Add existing variables to the form unless they are empty.
+  foreach ($existing_variables as $key => $data) {
+    _omniture_variable_form($form, $key, $data);
+  }
+  // Add one blank set of variable fields.
+  _omniture_variable_form($form, count($existing_variables));
+  $form['add_another_variable'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add another variable'),
+    '#submit' => array('omniture_add_another_variable_submit'),
+    '#limit_validation_errors' => array(),
+    '#ajax' => array(
+      'callback' => 'omniture_add_another_variable_js',
+      'wrapper' => 'omniture-variables-wrapper',
+      'effect' => 'fade',
+    ),
+  );
+  $form['tokens'] = array(
+    '#theme' => 'token_tree',
+    '#token_types' => array('node', 'menu', 'term', 'user'),
+    '#global_types' => TRUE,
+    '#click_insert' => TRUE,
+  );
+}
+
+/**
+ * Helper form builder for an individual variable.
+ */
+function _omniture_variable_form(&$form, $key, $data = array()) {
+  $form['omniture_variables'][$key]['name'] = array(
+    '#type' => 'textfield',
+    '#title_display' => 'invisible',
+    '#title' => t('Name'),
+    '#default_value' => isset($data['name']) ? $data['name'] : '',
+    '#parents' => array('omniture_variables', $key, 'name'),
+    '#attributes' => array('class' => array('field-variable-name')),
+  );
+  $form['omniture_variables'][$key]['value'] = array(
+    '#type' => 'textfield',
+    '#title_display' => 'invisible',
+    '#title' => t('Value'),
+    '#default_value' => isset($data['value']) ? $data['value'] : '',
+    '#parents' => array('omniture_variables', $key, 'value'),
+    '#attributes' => array('class' => array('field-variable-value')),
+  );
+  if (empty($data)) {
+    $form['omniture_variables'][$key]['name']['#description'] = t('Example: prop1');
+    $form['omniture_variables'][$key]['value']['#description'] = t('Example: [current-page:title]');
+  }
+}
+
+/**
+ * Validation function used by the variables form.
+ */
+function omniture_variables_form_validate($form, &$form_state) {
+  if ($form_state['triggering_element']['#value'] != t('Add another variable')) {
+    omniture_variables_trim_empties($form_state['values']);
+  }
+}
+
+/**
+ * Given the values entered into the omniture variables form, remove any empty
+ * variables (i.e. both "name" & "value" are blank).
+ */
+function omniture_variables_trim_empties(&$values, $parent = 'omniture_variables') {
+  foreach ($values as $key => &$val) {
+    if ($key === $parent) {
+      // We found the omniture variables.
+      foreach ($val as $k => $v) {
+        if (empty($val[$k]['name']) && empty($val[$k]['value'])) {
+          unset($val[$k]);
+        }
+      }
+      // Reset the array indexes to prevent wierd behavior caused by a variable
+      // being removed in the middle of the array.
+      $val = array_values($val);
+      break;
+    }
+    elseif (is_array($val)) {
+      omniture_variables_trim_empties($val, $parent);
+    }
+  }
+}
+
+/**
+ * AJAX callback function for adding variable fields to the settings form.
+ */
+function omniture_add_another_variable_js($form, $form_state) {
+  return $form['variables']['omniture_variables'];
+}
+
+/**
+ * Submit handler to add more variables.
+ */
+function omniture_add_another_variable_submit($form, &$form_state) {
+  $form_state['omniture_variables'] = $form_state['input']['omniture_variables'];
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Form validation.
+ */
+function omniture_admin_settings_validate($form, &$form_state) {
+  // Remove any empty variables.
+  foreach ($form_state['values']['omniture_variables'] as $key => $val) {
+    if (empty($val['name']) && empty($val['value'])) {
+      unset($form_state['values']['omniture_variables'][$key]);
+    }
+  }
+  $form_state['values']['omniture_variables'] = array_values($form_state['values']['omniture_variables']);
+}
+
+
+/**
  * Used to replace the value of omniture variables. The variables need to be
  * defined with hook_omniture_variables().
  *
@@ -244,3 +455,38 @@ function omniture_set_variable($name = NULL, $value = NULL) {
 function omniture_get_variables() {
   return omniture_set_variable();
 }
+
+/**
+ * Theme function for the "variables" form.
+ */
+function theme_omniture_variables($variables) {
+  $form = $variables['form'];
+
+  $add_button = drupal_render($form['add_another_variable']);
+  unset($form['add_another_variable']);
+
+  $headers = array(t('Name'), t('Value'));
+  $rows = array();
+  foreach (element_children($form) as $key) {
+    $rows[] = array(drupal_render($form[$key]['name']), drupal_render($form[$key]['value']));
+  }
+
+  return theme('table', array('header' => $headers, 'rows' => $rows)) . $add_button;
+}
+
+/**
+ * Create a data array to be used by token_replace().
+ *
+ * @return array
+ */
+function _omniture_get_token_context() {
+  $context = &drupal_static(__function__);
+
+  if (is_null($context)) {
+    $context['node'] = menu_get_object('node');
+    $context['term'] = menu_get_object('taxonomy_term', 2);
+    $context['menu'] = menu_load('main-menu');
+  }
+
+  return $context;
+}
diff --git a/plugins/context/omniture_reaction_variables.inc b/plugins/context/omniture_reaction_variables.inc
index e69de29..691b03d 100644
--- a/plugins/context/omniture_reaction_variables.inc
+++ b/plugins/context/omniture_reaction_variables.inc
@@ -0,0 +1,67 @@
+<?php
+
+class omniture_reaction_variables extends context_reaction {
+  /**
+   * Implements context_reaction::options_form()
+   *
+   * Allow users to specify varables that should be set for the given context.
+   */
+  function options_form($context) {
+    $settings = $this->fetch_from_context($context);
+
+    // Get the existing variables from context.
+    $existing_variables = isset($settings['omniture_variables']) ? $settings['omniture_variables'] : array();
+
+    // Build the variables form.
+    _omniture_variables_form($form, $existing_variables);
+
+    // Modify the #parents property to make sure values are stored in the
+    // location that contexts expects them.
+    $parents = array('reactions', 'plugins', $this->plugin);
+
+    foreach (element_children($form['omniture_variables']) as $key) {
+      if (is_numeric($key)) {
+        $form['omniture_variables'][$key]['name']['#parents'] = array_merge($parents, $form['omniture_variables'][$key]['name']['#parents']);
+        $form['omniture_variables'][$key]['value']['#parents'] = array_merge($parents, $form['omniture_variables'][$key]['value']['#parents']);
+      }
+    }
+
+    // Modify form to call the contexts-specific versions of certain functions.
+    $form['add_another_variable']['#submit'] = array('omniture_context_add_another_variable_submit');
+    $form['add_another_variable']['#ajax']['callback'] = 'omniture_context_add_another_variable_js';
+
+    return $form;
+  }
+
+  /**
+   * Implements context_reaction::execute()
+   *
+   * Return a list of variables based on the current context. Note that tokens
+   * will be replaced later in _omniture_format_variables().
+   */
+  function execute(&$variables) {
+    $settings = array();
+
+    foreach ($this->get_contexts() as $context) {
+      foreach ($context->reactions['omniture_vars']['omniture_variables'] as $key => $value) {
+        $variables[$value['name']] = $value['value'];
+      }
+    }
+    return $variables;
+  }
+}
+
+/**
+ * Submit handler to add more variables in the context reaction form.
+ */
+function omniture_context_add_another_variable_submit($form, &$form_state) {
+  $form_state['omniture_variables'] = $form_state['input']['reactions']['plugins'][$this->plugin];
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Ajax callback for adding more variables in the context reaction form.
+ */
+function omniture_context_add_another_variable_js($form, $form_state) {
+  return $form['reactions']['plugins'][$this->plugin]['omniture_variables'];
+}
