diff --git a/google_appliance.api.php b/google_appliance.api.php
index 6d6b152..b0c65a2 100644
--- a/google_appliance.api.php
+++ b/google_appliance.api.php
@@ -72,32 +72,18 @@ function hook_google_appliance_response_alter(Drupal\google_appliance\SearchResu
  *
  * Use this to alter the render array properties.
  *
- * @param $cluster_list
- *   A renderable array conforming to theme_item_list().
- *
- * @param $cluster_results
+ * @param \Drupal\Core\Link[] $cluster_list
+ *   Array of links.
+ * @param array $cluster_results
  *   The raw cluster results returned via the Google Appliance instance.
  *
- * @see google_appliance_get_clusters()
+ * @see \Drupal\google_appliance\Service\Search::getRelatedSearches
  * @see theme_item_list()
- *
- * @todo Update as appropriate.
  */
-function hook_google_appliance_cluster_list_alter(&$cluster_list, $cluster_results) {
-  // Add some CSS classes.
-  $cluster_list['#attributes']['class'][] = 'foo-list';
-  $cluster_list['#items'] = [];
-
-  // Construct a new list of links using the raw results with a custom path.
-  foreach ($cluster_results as $cluster) {
-    $cluster_list['#items'][] = Link::fromTextAndUrl(
-      $cluster['label'],
-      Url::fromUri('search/my/path/' . $cluster['label'])
-    )->toString();
+function hook_google_appliance_cluster_list_alter(array &$cluster_list, array $cluster_results) {
+  foreach ($cluster_list as $link) {
+    $link->getUrl()->setAbsolute(TRUE);
   }
-
-  // Change the first item of the list.
-  $cluster_list['#items'][0] = '<span>A new item</span>';
 }
 
 /**
diff --git a/google_appliance.module b/google_appliance.module
index f308646..a0b8bb1 100644
--- a/google_appliance.module
+++ b/google_appliance.module
@@ -34,7 +34,7 @@ function google_appliance_help($route_name, RouteMatchInterface $route_match) {
       break;
 
     case 'google_appliance.admin':
-      $output = '<p>' . t('The Google Appliance settings specify the interface to your GSA device. The search results obtained via that interface are controlled by the Google Search Appliance configuration itself. Visit the <a href="@gsa-help">Google Appliance help section</a> for more information on setting up the integration.', ['@gsa-help' => url('admin/help/google_appliance')]) . '</p>';
+      $output = '<p>' . t('The Google Appliance settings specify the interface to your GSA device. The search results obtained via that interface are controlled by the Google Search Appliance configuration itself. Visit the <a href="@gsa-help">Google Appliance help section</a> for more information on setting up the integration.', ['@gsa-help' => '/admin/help/google_appliance']) . '</p>';
       break;
   }
   return $output;
diff --git a/src/Plugin/Block/RelatedSearchesBlock.php b/src/Plugin/Block/RelatedSearchesBlock.php
new file mode 100644
index 0000000..88919b5
--- /dev/null
+++ b/src/Plugin/Block/RelatedSearchesBlock.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\google_appliance\Plugin\Block;
+
+use Drupal\Core\Block\BlockBase;
+
+/**
+ * Provides a 'Google Appliance Related Search' block.
+ *
+ * @Block(
+ *   id = "google_appliance_related_search",
+ *   admin_label = @Translation("Google Appliance Related Searches"),
+ *   category = @Translation("Search")
+ * )
+ */
+
+class RelatedSearchesBlock extends BlockBase{
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build() {
+    $searcher = \Drupal::service('google_appliance.search');
+    $routeMatch = \Drupal::service('current_route_match');
+    $query = $routeMatch->getParameter('search_query');
+    $results = $searcher->getRelatedSearches($query);
+    return ['#theme' => 'item_list', '#items' => $results];
+  }
+
+  public function getCacheContexts() {
+    return array_merge(parent::getCacheContexts(), ['url']);
+  }
+
+}
diff --git a/src/Service/Search.php b/src/Service/Search.php
index dec83a0..caef06a 100644
--- a/src/Service/Search.php
+++ b/src/Service/Search.php
@@ -5,6 +5,9 @@ namespace Drupal\google_appliance\Service;
 use Drupal\Component\Utility\Html;
 use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\Link;
+use Drupal\Core\Url;
+use Drupal\google_appliance\Routing\SearchViewRoute;
 use Drupal\google_appliance\SearchResults\ResultSet;
 use Drupal\google_appliance\SearchResults\SearchQuery;
 use GuzzleHttp\ClientInterface;
@@ -105,86 +108,55 @@ class Search implements SearchInterface {
       ->setResultsPerPage($resultsPerPage);
   }
 
-}
-
-// @todo: Finish these.
-
-/**
- * Get related search via the Google Search Appliance clustering service.
- *
- * @return
- *   themed list of links
- */
-function google_appliance_get_clusters() {
-
-  // Grab module settings.
-  $settings = _google_appliance_get_settings();
-
-  // Get the search query.
-  $query_pos = substr_count($settings['drupal_path'], '/') + 1;
-  $search_query = urldecode(arg($query_pos));
-  $cluster_content = NULL;
-
-  // Perform POST to acquire the clusters  block.
-  $clusterQueryURL = Html::escape($settings['hostname'] . '/cluster');
-  $clusterQueryParams = [
-    'q' => Html::escape($search_query),
-    'btnG' => 'Google+Search',
-    'access' => 'p',
-    'entqr' => '0',
-    'ud' => '1',
-    'sort' => 'date:D:L:d1',
-    'output' => 'xml_no_dtd',
-    'oe' => 'utf8',
-    'ie' => 'utf8',
-    'site' => Html::escape($settings['collection']),
-    'client' => Html::escape($settings['frontend']),
-  ];
-
-  // Alter request according to language filter settings.
-  if (\Drupal::moduleHandler()
-    ->moduleExists('locale') && $settings['language_filter_toggle']
-  ) {
-    $clusterQueryParams['lr'] = _google_appliance_get_lr($settings['language_filter_options']);
-  }
-
-  // cURL request for the clusters produces JSON result.
-  $gsa_clusters_json = _curl_post($clusterQueryURL, $clusterQueryParams);
-
-  // No error -> get the clusters.
-  if (!$gsa_clusters_json['is_error']) {
-
-    $clusters = json_decode($gsa_clusters_json['response'], TRUE);
-
-    if (isset($clusters['clusters'][0])) {
-
-      // Build the link list.
-      $cluster_list_items = [];
-      foreach ($clusters['clusters'][0]['clusters'] as $cluster) {
-        // @FIXME
-        // l() expects a Url object, created from a route name or external URI.
-        // array_push($cluster_list_items, l($cluster['label'], $settings['drupal_path'] . '/' . $cluster['label']));
-      }
-
-      // Create theme-friendly list of links render array.
-      $cluster_list = [
-        '#theme' => 'item_list',
-        '#items' => $cluster_list_items,
-        '#title' => NULL,
-        '#type' => 'ul',
-        '#attributes' => [],
+  /**
+   * Gets related searches.
+   *
+   * @param string $searchPhrase
+   *   Search phrase.
+   *
+   * @return \Drupal\Core\Link[]
+   *   Array of related search links.
+   */
+  public function getRelatedSearches($searchPhrase) {
+    $config = $this->configFactory->get('google_appliance.settings');
+    $links = [];
+    try {
+      $params = [
+        'q' => $searchPhrase,
+        'btnG' => 'Google+Search',
+        'access' => 'p',
+        'entqr' => '0',
+        'ud' => '1',
+        'sort' => 'date:D:L:d1',
+        'output' => 'xml_no_dtd',
+        'oe' => 'utf8',
+        'ie' => 'utf8',
+        'client' => Html::escape($config->get('connection_info.frontend')),
+        'site' => Html::escape($config->get('connection_info.collection')),
       ];
-
-      // Allow implementation of hook_google_appliance_cluster_list_alter() by
-      // other modules.
-      \Drupal::moduleHandler()
-        ->alter('google_appliance_cluster_list', $cluster_list, $cluster_results);
-
-      $cluster_content = \Drupal::service('renderer')->render($cluster_list);
+      $response = $this->httpClient->request('POST', $config->get('connection_info.hostname') . '/cluster', [
+        'form_params' => $params,
+      ]);
+      $response = json_decode((string) $response->getBody(), TRUE);
+      if (isset($response['clusters'][0])) {
+
+        // Build the link list.
+        $cluster_list_items = [];
+        foreach ($response['clusters'][0]['clusters'] as $cluster) {
+          $links[] = Link::fromTextAndUrl($cluster['label'], Url::fromRoute(SearchViewRoute::ROUTE_NAME, [
+            'search_query' => $cluster['label'],
+          ]));
+        }
+
+        $this->moduleHandler->alter('google_appliance_cluster_list', $links, $response);
+      }
+    }
+    catch (GuzzleException $e) {
+      return [];
     }
+    return $links;
   }
 
-  return $cluster_content;
 }
 
 /**
diff --git a/src/Service/SearchInterface.php b/src/Service/SearchInterface.php
index a5c837f..ec0744e 100644
--- a/src/Service/SearchInterface.php
+++ b/src/Service/SearchInterface.php
@@ -20,4 +20,15 @@ interface SearchInterface {
    */
   public function search(SearchQuery $query);
 
+  /**
+   * Gets related searches.
+   *
+   * @param string $searchPhrase
+   *   Search phrase.
+   *
+   * @return \Drupal\Core\Link[]
+   *   Array of related search links.
+   */
+  public function getRelatedSearches($searchPhrase);
+
 }
diff --git a/tests/modules/google_appliance_test/src/TestSearch.php b/tests/modules/google_appliance_test/src/TestSearch.php
index 831efa2..7d4fe94 100644
--- a/tests/modules/google_appliance_test/src/TestSearch.php
+++ b/tests/modules/google_appliance_test/src/TestSearch.php
@@ -2,6 +2,9 @@
 
 namespace Drupal\google_appliance_test;
 
+use Drupal\Core\Link;
+use Drupal\Core\Url;
+use Drupal\google_appliance\Routing\SearchViewRoute;
 use Drupal\google_appliance\SearchResults\ResultSet;
 use Drupal\google_appliance\SearchResults\Result;
 use Drupal\google_appliance\SearchResults\SearchQuery;
@@ -34,4 +37,18 @@ class TestSearch extends Search {
       ->setResultsPerPage($perPage);
   }
 
+  /**
+   * {@inheritdoc}
+   */
+  public function getRelatedSearches($searchPhrase) {
+    $phrases = ['foo', 'bar'];
+    $links = [];
+    foreach ($phrases as $phrase) {
+      Link::fromTextAndUrl($phrase, Url::fromRoute(SearchViewRoute::ROUTE_NAME, [
+        'search_query' => $phrase,
+      ]));
+    }
+    return $links;
+  }
+
 }
diff --git a/tests/src/Functional/ReleatedSearchesBlockTest.php b/tests/src/Functional/ReleatedSearchesBlockTest.php
new file mode 100644
index 0000000..bbd1897
--- /dev/null
+++ b/tests/src/Functional/ReleatedSearchesBlockTest.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Drupal\Tests\google_appliance\Functional;
+
+use Drupal\google_appliance\Routing\SearchViewRoute;
+use Drupal\Core\Url;
+
+/**
+ * Test related search block.
+ *
+ * @group google_appliance
+ */
+class ReleatedSearchesBlockTest extends GoogleApplianceFunctionalTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'google_appliance_test',
+  ];
+
+  /**
+   * Test search block form.
+   */
+  public function testSearchBlock() {
+    $this->placeBlock('google_appliance_search');
+    $this->placeBlock('google_appliance_related', [
+      'visibility' => [
+        'request_path' => [
+          'pages' => 'search',
+          'negate' => FALSE,
+        ],
+      ],
+    ]);
+
+    // Test redirect.
+    // Go to the front page and submit the search form.
+    $this->drupalGet(Url::fromRoute('<front>'));
+    $terms = ['search_keys' => 'ponies'];
+    $this->submitForm($terms, t('Search'));
+
+    $this->assertEquals(Url::fromRoute(SearchViewRoute::ROUTE_NAME, [
+      'search_query' => 'ponies',
+    ])->setAbsolute()->toString(), $this->getSession()->getCurrentUrl());
+    $assert = $this->assertSession();
+    $assert->statusCodeEquals(200);
+    $assert->linkByHrefExists(Url::fromRoute(SearchViewRoute::ROUTE_NAME, [
+      'search_query' => 'foo',
+    ])->toString());
+    $assert->linkByHrefExists(Url::fromRoute(SearchViewRoute::ROUTE_NAME, [
+      'search_query' => 'bar',
+    ])->toString());
+    $assert->linkExists('foo');
+    $assert->linkExists('bar');
+  }
+
+}
