diff --git a/includes/webform.pages.inc b/includes/webform.pages.inc
index bfa0a38..23e76a3 100644
--- a/includes/webform.pages.inc
+++ b/includes/webform.pages.inc
@@ -64,7 +64,7 @@ function webform_configure_form($form, &$form_state, $node) {
     '#type' => 'item',
     '#title' => t('Redirection location'),
     '#theme' => 'webform_advanced_redirection_form',
-    '#description' => t('Choose where to redirect the user upon successful submission.') . ' ' . t('The <em>Custom URL</em> option supports Webform token replacements.') . ' ' . theme('webform_token_help', array('groups' => array('node', 'submission'))),
+    '#description' => t('Choose where to redirect the user upon successful submission.') . ' ' . t('The <em>Custom URL</em> option supports token replacements for query string values.') . ' ' . theme('webform_token_help', array('groups' => array('node', 'submission'))),
   );
   $form['submission']['redirection']['redirect']= array(
     '#type' => 'radios',
diff --git a/webform.module b/webform.module
index e02deea..e841ca1 100644
--- a/webform.module
+++ b/webform.module
@@ -3032,13 +3032,6 @@ function webform_client_form_submit($form, &$form_state) {
   $confirmation = strlen(trim(strip_tags($node->webform['confirmation']))) ? $node->webform['confirmation'] : '';
   $confirmation = webform_replace_tokens($confirmation, $node, $submission, NULL, TRUE);
 
-  // Clean up the redirect URL and filter it for webform tokens.
-  $redirect_url = trim($node->webform['redirect_url']);
-  $redirect_url = webform_replace_tokens($redirect_url, $node, $submission);
-
-  // Remove the domain name from the redirect.
-  $redirect_url = preg_replace('/^' . preg_quote($GLOBALS['base_url'], '/') . '\//', '', $redirect_url);
-
   // Check confirmation and redirect_url fields.
   $message = NULL;
   $redirect = NULL;
@@ -3052,22 +3045,32 @@ function webform_client_form_submit($form, &$form_state) {
   elseif (!empty($form_state['values']['details']['finished'])) {
     $message = t('Submission updated.');
   }
-  elseif ($redirect_url == '<none>') {
+  elseif ($node->webform['redirect_url'] == '<none>') {
     $redirect = NULL;
   }
-  elseif ($redirect_url == '<confirmation>') {
+  elseif ($node->webform['redirect_url'] == '<confirmation>') {
     $query = array('sid' => $sid);
     if ((int) $user->uid === 0) {
       $query['token'] = md5($submission->submitted . $submission->sid . drupal_get_private_key());
     }
     $redirect = array('node/' . $node->nid . '/done', array('query' => $query));
   }
-  elseif (valid_url($redirect_url, TRUE)) {
-    $redirect = $redirect_url;
-    $external_url = TRUE;
-  }
-  elseif ($redirect_url && strpos($redirect_url, 'http') !== 0) {
-    $redirect = $redirect_url;
+  else {
+    // Clean up the redirect URL, filter it for tokens and remove the domain name.
+    $redirect_url = trim($node->webform['redirect_url']);
+    $redirect_url = webform_replace_query_string_tokens($redirect_url, $node, $submission);
+    $redirect_url = preg_replace('/^' . preg_quote($GLOBALS['base_url'], '/') . '\//', '', $redirect_url);
+
+    // $redirect_url is an absolute, external URL
+    if (valid_url($redirect_url, TRUE)) {
+      $redirect = $redirect_url;
+      $external_url = TRUE;
+    }
+    elseif ($redirect_url && strpos($redirect_url, 'http') !== 0) {
+      // Pass URL as an array so we support a query string and/or fragment.
+      $parsed_url = drupal_parse_url($redirect_url);
+      $redirect = array('path' => $parsed_url['path'], $parsed_url);
+    }
   }
 
   // Show a message if manually set.
@@ -3547,6 +3550,38 @@ function webform_replace_tokens($string, $node = NULL, $submission = NULL, $emai
 }
 
 /**
+ * Replace tokens entered as query string values in a URL.
+ *
+ * @param string $redirect_url
+ *   The redirect URL, with everything other than tokens already url encoded.
+ * @param $node
+ *   If replacing node-level tokens, the node for which tokens will be created.
+ * @param $submission
+ *   If replacing submission-level tokens, the submission for which tokens will
+ *   be created.
+ * @return string
+ *   The parsed and url encoded URL
+ */
+function webform_replace_query_string_tokens($redirect_url, $node = NULL, $submission = NULL) {
+  $token_data = array();
+  if ($node) {
+    $token_data['node'] = $node;
+  }
+  if ($submission) {
+    $token_data['webform-submission'] = $submission;
+  }
+
+  $parsed_redirect_url = drupal_parse_url($redirect_url);
+  if (!empty($parsed_redirect_url['query'])) {
+    foreach ($parsed_redirect_url['query'] as $key => $value) {
+      $parsed_redirect_url['query'][$key] = token_replace($value, $token_data, array('clear' => true, 'sanitize' => FALSE));
+    }
+    $redirect_url = url($parsed_redirect_url['path'], $parsed_redirect_url);
+  }
+  return $redirect_url;
+}
+
+/**
  * Replace tokens in descriptions and sanitize according to Webform settings.
  */
 function webform_filter_descriptions($string, $node = NULL, $submission = NULL) {
