diff --git a/collect.routing.yml b/collect.routing.yml
index 6c41ece..3b65831 100644
--- a/collect.routing.yml
+++ b/collect.routing.yml
@@ -105,3 +105,11 @@ collect.settings:
     _title: 'Collect settings'
   requirements:
     _permission: 'administer collect'
+
+collect.generate_page:
+  path: '/admin/content/collect/{collect_container}/page'
+  defaults:
+    _controller: 'Drupal\collect\Controller\GenerateWebPageController::generatePage'
+  requirements:
+    _custom_access: 'Drupal\collect\Controller\GenerateWebPageController::checkAccess'
+    _csrf_token: 'TRUE'
diff --git a/src/Controller/GenerateWebPageController.php b/src/Controller/GenerateWebPageController.php
new file mode 100644
index 0000000..cbdea1b
--- /dev/null
+++ b/src/Controller/GenerateWebPageController.php
@@ -0,0 +1,73 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\collect\Controller\GenerateWebPageController.
+ */
+
+namespace Drupal\collect\Controller;
+
+use Drupal\collect\CollectContainerInterface;
+use Drupal\collect\Plugin\collect\Schema\FetchUrlSchema;
+use Drupal\collect\Schema\SchemaManagerInterface;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Controller\ControllerBase;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Generate Web Page Controller.
+ */
+class GenerateWebPageController extends ControllerBase {
+
+  /**
+   * The injected schema plugin manager.
+   *
+   * @var \Drupal\collect\Schema\SchemaManagerInterface
+   */
+  protected $schemaManager;
+
+  /**
+   * Constructs a new GenerateWebPageController.
+   *
+   * @param \Drupal\collect\Schema\SchemaManagerInterface $schema_manager
+   *   Injected schema manager.
+   */
+  public function __construct(SchemaManagerInterface $schema_manager) {
+    $this->schemaManager = $schema_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('plugin.manager.collect.schema')
+    );
+  }
+
+  /**
+   * Generates a web page from raw html/json data.
+   */
+  public function generatePage(CollectContainerInterface $collect_container) {
+    $data = json_decode($collect_container->getData(), TRUE);
+    $content = $data['body'];
+    if (!is_string($content)) {
+      $content = json_encode($content);
+    }
+    $accept_header = 'text/html';
+    if (!empty($data['response-headers']['Content-Type'])) {
+      $accept_header = $data['response-headers']['Content-Type'][0];
+    }
+    return new Response($content, 200, ['Content-Type' => $accept_header]);
+  }
+
+  /**
+   * Checks whether user has permission to generate a web page.
+   */
+  public function checkAccess(CollectContainerInterface $collect_container) {
+    $access = AccessResult::allowedIfHasPermission(\Drupal::currentUser(), 'administer collect');
+    $schema = $this->schemaManager->createInstanceFromUri($collect_container->getSchemaUri());
+    $has_fetch_url_plugin = $schema instanceof FetchUrlSchema ? TRUE : FALSE;
+    return $access->andIf($has_fetch_url_plugin ? AccessResult::allowed() : AccessResult::forbidden());
+  }
+}
diff --git a/src/Plugin/collect/Schema/FetchUrlSchema.php b/src/Plugin/collect/Schema/FetchUrlSchema.php
new file mode 100644
index 0000000..0bd48b2
--- /dev/null
+++ b/src/Plugin/collect/Schema/FetchUrlSchema.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * @file
+ * Contains \Drupal\collect\Plugin\collect\Schema\FetchUrlSchema.
+ */
+
+namespace Drupal\collect\Plugin\collect\Schema;
+
+use Drupal\collect\Plugin\Field\FieldType\CollectDataItem;
+use Drupal\collect\Schema\SchemaBase;
+use Drupal\Core\TypedData\ComplexDataInterface;
+use Drupal\Core\TypedData\DataDefinition;
+use Drupal\Core\Url;
+
+/**
+ * Schema plugin for captured web pages.
+ *
+ * @Schema(
+ *   id = "collect_fetch_url",
+ *   label = @Translation("Collect Fetch URL"),
+ *   patterns = {
+ *     "http://schema.md-systems.ch/collect/0.0.1/url"
+ *   }
+ * )
+ */
+class FetchUrlSchema extends SchemaBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function parse(CollectDataItem $data_field) {
+    $data = json_decode($data_field->data, TRUE);
+
+    // If decoding fails, there are no fields.
+    if (json_last_error()) {
+      return array();
+    }
+
+    return $data;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function build($data) {
+    if (empty($data)) {
+      return;
+    }
+    $output = array();
+    $output['request-headers'] = array(
+      '#type' => 'table',
+      '#header' => [$this->t('Request headers'), NULL],
+      '#empty' => $this->t('There are no data.'),
+      '#prefix' => '<div id="request-table-wrapper">',
+      '#suffix' => '</div>',
+    );
+
+    foreach ($data['request-headers'] as $key => $value) {
+      $output['request-headers'][$key] = array(
+        ['#markup' => $key],
+        ['#markup' => $value[0]],
+      );
+    }
+
+    $output['response-headers'] = array(
+      '#type' => 'table',
+      '#header' => [$this->t('Response headers'), NULL],
+      '#empty' => $this->t('There are no data.'),
+      '#prefix' => '<div id="response-table-wrapper">',
+      '#suffix' => '</div>',
+    );
+
+    foreach ($data['response-headers'] as $key => $value) {
+      $output['response-headers'][$key] = array(
+        ['#markup' => $key],
+        ['#markup' => $value[0]],
+      );
+    }
+
+    $current_url = explode('/', \Drupal::requestStack()->getCurrentRequest()->getRequestUri());
+    $collect_container_id = end($current_url);
+    $url = \Drupal::url('collect.generate_page', ['collect_container' => $collect_container_id], ['absolute' => TRUE]);
+    $output['body'] = array(
+      '#type' => 'link',
+      '#attributes' => array(
+        'class' => 'button',
+        'target' => '_blank',
+      ),
+      '#title' => $this->t('Show content in a new window'),
+      '#url' => Url::fromUri($url),
+    );
+
+    return $output;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function buildTeaser($data) {
+    $output = array();
+    $output['web_page'] = array(
+      '#type' => 'item',
+      '#title' => $this->t('Web page data'),
+      '#markup' => [$this->t('Request headers'), $this->t('Response headers'), $this->t('Body')],
+    );
+
+    return $output;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getDataProperty(ComplexDataInterface $data, $property_name) {
+    return $data[$property_name];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getStaticPropertyDefinitions() {
+    $properties = DataDefinition::create('string')->setLabel('Data');
+    return $properties;
+  }
+}
diff --git a/src/Schema/SchemaBase.php b/src/Schema/SchemaBase.php
index 6f04e5f..79a6bfe 100644
--- a/src/Schema/SchemaBase.php
+++ b/src/Schema/SchemaBase.php
@@ -76,6 +76,7 @@ abstract class SchemaBase extends PluginBase implements SchemaInterface, SchemaT
       'label' => $this->t('@label (suggested)', ['@label' => $this->getLabel()]),
       'uri_pattern' => $container->getSchemaUri(),
       'plugin_id' => $this->getPluginId(),
+      'container_revision' => TRUE,
     ));
   }
 
diff --git a/src/Tests/CollectJsonTest.php b/src/Tests/CollectJsonTest.php
index b5903e9..e2477e2 100644
--- a/src/Tests/CollectJsonTest.php
+++ b/src/Tests/CollectJsonTest.php
@@ -59,7 +59,7 @@ class CollectJsonTest extends KernelTestBase {
       'id' => 'collect_json_global_fields',
       'uri_pattern' => 'http://schema.md-systems.ch/collect/0.0.1/collectjson-definition/global/fields',
       'plugin_id' => 'collectjson',
-      'container_revision' => 1,
+      'container_revision' => TRUE,
     ]);
     $fields_schema->save();
 
diff --git a/src/Tests/CollectWebTest.php b/src/Tests/CollectWebTest.php
index dcff69a..5ea6cf5 100644
--- a/src/Tests/CollectWebTest.php
+++ b/src/Tests/CollectWebTest.php
@@ -127,13 +127,27 @@ class CollectWebTest extends WebTestBase {
     $this->clickLink(t('View'));
     $this->assertLink($url);
 
-    // Test body content and empty Accept header.
+    // Assert Fetch URL schema suggestion is displayed.
+    // Assert the schema is applied.
+    $this->clickLink(t('Collect Fetch URL schema'));
+    $this->drupalPostForm(NULL, array(
+      'label' => 'Collect Fetch URL',
+      'id' => 'collect_fetch_url',
+      'uri_pattern' => 'http://schema.md-systems.ch/collect/0.0.1/url',
+      'plugin_id' => 'collect_fetch_url',
+      'container_revision' => TRUE,
+    ), t('Save'));
+    $this->assertText(t('Schema config Collect Fetch URL has been saved.'));
+
+    // Assert empty Accept header.
+    // Assert that body content on the generated web page is equal to the body
+    // content stored in collect container.
+    $this->clickLink(t('Show content in a new window'));
     $first_url_container_id = $this->getLatestId();
     $data = json_decode(Container::load($first_url_container_id)->getData(), TRUE);
     $this->assertEqual($data['request-headers']['Accept'][0], '');
     $body = $data['body'];
-    $this->setRawContent($body);
-    $this->assertRaw('<!DOCTYPE html><html><body><h1>Test body</h1><p>Test paragraph.</p></body></html>');
+    $this->assertEqual($body, $this->getRawContent());
 
     // Test Fetch URL form to page that does not exist.
     $this->captureWebPage(404);
@@ -229,7 +243,7 @@ class CollectWebTest extends WebTestBase {
       'id' => 'collect_field_definition',
       'uri_pattern' => 'http://schema.md-systems.ch/collect/0.0.1/collectjson-definition/global/fields',
       'plugin_id' => 'collect_field_definition',
-      'container_revision' => 1,
+      'container_revision' => TRUE,
     ), t('Save'));
     $this->assertText(t('Node ID') . ' (nid)');
 
@@ -238,7 +252,7 @@ class CollectWebTest extends WebTestBase {
     $this->clickLink(t('Collect JSON schema'));
     $this->drupalPostForm(NULL, array(
       'id' => 'collect_json_node_article',
-      'container_revision' => 1,
+      'container_revision' => TRUE,
     ), t('Save'));
 
     // Edit an article to test continuous entity update.
