diff --git a/opentech/apply/funds/models/submissions.py b/opentech/apply/funds/models/submissions.py
index 593bca48a04f9752bbb0ec6d1b44cad49289e7ab..0151cb79e8d310de298eb0a316716095d0a32fc5 100644
--- a/opentech/apply/funds/models/submissions.py
+++ b/opentech/apply/funds/models/submissions.py
@@ -6,7 +6,7 @@ from django.contrib.auth import get_user_model
 from django.contrib.postgres.fields import JSONField
 from django.core.exceptions import PermissionDenied
 from django.db import models
-from django.db.models import Count, IntegerField, OuterRef, Subquery, Sum, Q
+from django.db.models import Count, IntegerField, OuterRef, Subquery, Sum, Q, Prefetch
 from django.db.models.expressions import RawSQL, OrderBy
 from django.db.models.functions import Coalesce
 from django.dispatch import receiver
@@ -21,6 +21,7 @@ from wagtail.contrib.forms.models import AbstractFormSubmission
 
 from opentech.apply.activity.messaging import messenger, MESSAGES
 from opentech.apply.determinations.models import Determination
+from opentech.apply.review.models import Review, ReviewOpinion
 from opentech.apply.review.options import AGREE
 from opentech.apply.stream_forms.blocks import UploadableMediaBlock
 from opentech.apply.stream_forms.files import StreamFieldDataEncoder
@@ -143,7 +144,11 @@ class ApplicationSubmissionQueryset(JSONOrderable):
             ),
             role_icon=Subquery(roles_for_review[:1].values('role__icon')),
         ).prefetch_related(
-            'reviews__author'
+            Prefetch(
+                'reviews', queryset=Review.objects.select_related('author').prefetch_related(
+                    Prefetch('opinions', queryset=ReviewOpinion.objects.select_related('author'))
+                )
+            )
         ).select_related(
             'page',
             'round',
diff --git a/opentech/apply/funds/templates/funds/includes/review_sidebar_item.html b/opentech/apply/funds/templates/funds/includes/review_sidebar_item.html
index be0bba5a1275fcdfecc6d6f717fddc1b7adf7df0..1f03ab252075094aad321f72a0758d7dd1728d92 100644
--- a/opentech/apply/funds/templates/funds/includes/review_sidebar_item.html
+++ b/opentech/apply/funds/templates/funds/includes/review_sidebar_item.html
@@ -9,7 +9,7 @@
         <div>-</div>
         <div>-</div>
     {% else %}
-        {% if request.user.is_apply_staff or request.user == reviewer %}
+        {% if request.user == reviewer or request.user.is_reviewer and review.reviewer_visibility or request.user.is_apply_staff %}
             <div>
                 <a href="{% url 'apply:submissions:reviews:review' submission_pk=review.submission.id pk=review.id %}">
                     <div class="reviews-sidebar__name">
diff --git a/opentech/apply/review/blocks.py b/opentech/apply/review/blocks.py
index 1edebc7db987e4753a9c69ad8fac1348bf6f55f2..6528f55c23bc13afcd3ca4729c05c5785aafefb7 100644
--- a/opentech/apply/review/blocks.py
+++ b/opentech/apply/review/blocks.py
@@ -2,12 +2,13 @@ import json
 
 from django import forms
 
+from django.utils.safestring import mark_safe
 from django.utils.translation import ugettext_lazy as _
 
 from wagtail.core.blocks import RichTextBlock
 
 from opentech.apply.review.fields import ScoredAnswerField
-from opentech.apply.review.options import RECOMMENDATION_CHOICES, RATE_CHOICES_DICT, RATE_CHOICE_NA
+from opentech.apply.review.options import RECOMMENDATION_CHOICES, RATE_CHOICES_DICT, RATE_CHOICE_NA, VISIBILITY, VISIBILILTY_HELP_TEXT, PRIVATE
 from opentech.apply.stream_forms.blocks import OptionalFormFieldBlock, CharFieldBlock, TextFieldBlock, CheckboxFieldBlock, DropdownFieldBlock
 from opentech.apply.utils.blocks import CustomFormFieldsBlock, MustIncludeFieldBlock
 from opentech.apply.utils.options import RICH_TEXT_WIDGET_SHORT
@@ -75,6 +76,25 @@ class RecommendationCommentsBlock(ReviewMustIncludeFieldBlock):
         return kwargs
 
 
+class VisibilityBlock(ReviewMustIncludeFieldBlock):
+    name = 'visibility'
+    description = 'Visibility'
+    field_class = forms.ChoiceField
+    widget = forms.RadioSelect()
+
+    class Meta:
+        icon = 'radio-empty'
+
+    def get_field_kwargs(self, struct_value):
+        kwargs = super(VisibilityBlock, self).get_field_kwargs(struct_value)
+        kwargs['choices'] = VISIBILITY.items()
+        kwargs['initial'] = PRIVATE
+        kwargs['help_text'] = mark_safe('<br>'.join(
+            [VISIBILITY[choice] + ': ' + VISIBILILTY_HELP_TEXT[choice] for choice in VISIBILITY]
+        ))
+        return kwargs
+
+
 class ReviewCustomFormFieldsBlock(CustomFormFieldsBlock):
     char = CharFieldBlock(group=_('Fields'))
     text = TextFieldBlock(group=_('Fields'))
diff --git a/opentech/apply/review/forms.py b/opentech/apply/review/forms.py
index 0d29c09ea311ac510dadc7422f527ce0ad0dfc38..fba3b158d5543fadf37a76b6394d4bdcfe53fb2b 100644
--- a/opentech/apply/review/forms.py
+++ b/opentech/apply/review/forms.py
@@ -6,7 +6,7 @@ from opentech.apply.review.options import NA
 from opentech.apply.stream_forms.forms import StreamBaseForm
 
 from .models import Review, ReviewOpinion
-from .options import OPINION_CHOICES
+from .options import OPINION_CHOICES, PRIVATE
 
 
 class MixedMetaClass(type(StreamBaseForm), type(forms.ModelForm)):
@@ -18,13 +18,14 @@ class ReviewModelForm(StreamBaseForm, forms.ModelForm, metaclass=MixedMetaClass)
 
     class Meta:
         model = Review
-        fields = ['recommendation', 'score', 'submission', 'author']
+        fields = ['recommendation', 'visibility', 'score', 'submission', 'author']
 
         widgets = {
             'recommendation': forms.HiddenInput(),
             'score': forms.HiddenInput(),
             'submission': forms.HiddenInput(),
             'author': forms.HiddenInput(),
+            'visibility': forms.HiddenInput(),
         }
 
         error_messages = {
@@ -65,6 +66,12 @@ class ReviewModelForm(StreamBaseForm, forms.ModelForm, metaclass=MixedMetaClass)
         self.instance.score = self.calculate_score(self.cleaned_data)
         self.instance.recommendation = int(self.cleaned_data[self.instance.recommendation_field.id])
         self.instance.is_draft = self.draft_button_name in self.data
+        # Old review forms do not have the requred visability field.
+        # This will set visibility to PRIVATE by default.
+        try:
+            self.instance.visibility = self.cleaned_data[self.instance.visibility_field.id]
+        except AttributeError:
+            self.instance.visibility = PRIVATE
 
         self.instance.form_data = self.cleaned_data['form_data']
 
diff --git a/opentech/apply/review/migrations/0016_review_visibility.py b/opentech/apply/review/migrations/0016_review_visibility.py
new file mode 100644
index 0000000000000000000000000000000000000000..3eb9e363a61c17a7a537f4540390b2808d3a9120
--- /dev/null
+++ b/opentech/apply/review/migrations/0016_review_visibility.py
@@ -0,0 +1,31 @@
+# Generated by Django 2.0.9 on 2018-12-12 17:48
+
+from django.db import migrations, models
+import wagtail.core.blocks
+import wagtail.core.blocks.static_block
+import wagtail.core.fields
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('review', '0015_review_opinion'),
+    ]
+
+    operations = [
+        migrations.AddField(
+            model_name='review',
+            name='visibility',
+            field=models.CharField(choices=[('private', 'Private'), ('reviewers', 'Reviewers and Staff')], default='private', max_length=10, verbose_name='Visibility'),
+        ),
+        migrations.AlterField(
+            model_name='review',
+            name='form_fields',
+            field=wagtail.core.fields.StreamField([('rich_text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('markdown_text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('char', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.core.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.core.blocks.CharBlock(label='Default value', required=False))], group='Fields')), ('text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('text_markup', wagtail.core.blocks.RichTextBlock(group='Fields', label='Paragraph')), ('score', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False))], group='Fields')), ('checkbox', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.BooleanBlock(required=False))], group='Fields')), ('dropdown', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Choice')))], group='Fields')), ('recommendation', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required')), ('comments', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required')), ('visibility', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required'))]),
+        ),
+        migrations.AlterField(
+            model_name='reviewform',
+            name='form_fields',
+            field=wagtail.core.fields.StreamField([('rich_text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('markdown_text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('char', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('format', wagtail.core.blocks.ChoiceBlock(choices=[('email', 'Email'), ('url', 'URL')], label='Format', required=False)), ('default_value', wagtail.core.blocks.CharBlock(label='Default value', required=False))], group='Fields')), ('text', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.TextBlock(label='Default value', required=False))], group='Fields')), ('text_markup', wagtail.core.blocks.RichTextBlock(group='Fields', label='Paragraph')), ('score', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False))], group='Fields')), ('checkbox', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('default_value', wagtail.core.blocks.BooleanBlock(required=False))], group='Fields')), ('dropdown', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('required', wagtail.core.blocks.BooleanBlock(label='Required', required=False)), ('choices', wagtail.core.blocks.ListBlock(wagtail.core.blocks.CharBlock(label='Choice')))], group='Fields')), ('recommendation', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required')), ('comments', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required')), ('visibility', wagtail.core.blocks.StructBlock([('field_label', wagtail.core.blocks.CharBlock(label='Label')), ('help_text', wagtail.core.blocks.TextBlock(label='Help text', required=False)), ('info', wagtail.core.blocks.static_block.StaticBlock())], group=' Required'))]),
+        ),
+    ]
diff --git a/opentech/apply/review/models.py b/opentech/apply/review/models.py
index bd5f083d2e3f361f8e940cf242bd1baebea9be66..c8ea72569e8e5d4ef6989b5d1cdead21d899c7a0 100644
--- a/opentech/apply/review/models.py
+++ b/opentech/apply/review/models.py
@@ -5,13 +5,12 @@ from django.db import models
 from django.db.models.signals import post_save
 from django.dispatch import receiver
 from django.urls import reverse
+from django.utils.functional import cached_property
 from django.utils.translation import ugettext_lazy as _
 from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
 from wagtail.core.fields import StreamField
 
-from opentech.apply.funds.models import AssignedReviewers
 from opentech.apply.funds.models.mixins import AccessFormData
-from opentech.apply.review.options import YES, NO, MAYBE, RECOMMENDATION_CHOICES, OPINION_CHOICES
 from opentech.apply.stream_forms.models import BaseStreamForm
 from opentech.apply.users.models import User
 
@@ -20,8 +19,9 @@ from .blocks import (
     RecommendationBlock,
     RecommendationCommentsBlock,
     ScoreFieldBlock,
+    VisibilityBlock,
 )
-from .options import NA
+from .options import NA, YES, NO, MAYBE, RECOMMENDATION_CHOICES, OPINION_CHOICES, VISIBILITY, PRIVATE, REVIEWER
 
 
 class ReviewFormFieldsMixin(models.Model):
@@ -38,6 +38,10 @@ class ReviewFormFieldsMixin(models.Model):
     def recommendation_field(self):
         return self._get_field_type(RecommendationBlock)
 
+    @property
+    def visibility_field(self):
+        return self._get_field_type(VisibilityBlock)
+
     @property
     def comment_field(self):
         return self._get_field_type(RecommendationCommentsBlock)
@@ -129,6 +133,7 @@ class Review(ReviewFormFieldsMixin, BaseStreamForm, AccessFormData, models.Model
     is_draft = models.BooleanField(default=False, verbose_name=_("Draft"))
     created_at = models.DateTimeField(verbose_name=_("Creation time"), auto_now_add=True)
     updated_at = models.DateTimeField(verbose_name=_("Update time"), auto_now=True)
+    visibility = models.CharField(verbose_name=_("Visibility"), choices=VISIBILITY.items(), default=PRIVATE, max_length=10)
 
     # Meta: used for migration purposes only
     drupal_id = models.IntegerField(null=True, blank=True, editable=False)
@@ -164,9 +169,14 @@ class Review(ReviewFormFieldsMixin, BaseStreamForm, AccessFormData, models.Model
     def get_compare_url(self):
         return self.revision.get_compare_url_to_latest()
 
+    @cached_property
+    def reviewer_visibility(self):
+        return self.visibility == REVIEWER
+
 
 @receiver(post_save, sender=Review)
 def update_submission_reviewers_list(sender, **kwargs):
+    from opentech.apply.funds.models import AssignedReviewers
     review = kwargs.get('instance')
 
     # Make sure the reviewer is in the reviewers list on the submission
diff --git a/opentech/apply/review/options.py b/opentech/apply/review/options.py
index 84cec661736272f372f528805055a4c2fd0868fb..3bcdde01898dc5f5a613c431a634938111af73d1 100644
--- a/opentech/apply/review/options.py
+++ b/opentech/apply/review/options.py
@@ -29,3 +29,16 @@ OPINION_CHOICES = (
     (AGREE, 'Agree'),
     (DISAGREE, 'Disagree'),
 )
+
+PRIVATE = 'private'
+REVIEWER = 'reviewers'
+
+VISIBILILTY_HELP_TEXT = {
+    PRIVATE: 'Visible only to staff.',
+    REVIEWER: 'Visible to other reviewers and staff.',
+}
+
+VISIBILITY = {
+    PRIVATE: 'Private',
+    REVIEWER: 'Reviewers and Staff',
+}
diff --git a/opentech/apply/review/templates/review/review_detail.html b/opentech/apply/review/templates/review/review_detail.html
index ef40757784276d254162cf1db75854d36e3bd698..fc0265dca511f9f59802668bf29c737144ca6b53 100644
--- a/opentech/apply/review/templates/review/review_detail.html
+++ b/opentech/apply/review/templates/review/review_detail.html
@@ -20,6 +20,10 @@
         <h5>Score</h5>
         <p>{{ review.score }}</p>
     </div>
+    <div>
+        <svg class="icon icon--eye"><use xlink:href="#eye"></use></svg>
+        {{ review.get_visibility_display }}
+    </div>
     {% if not review.for_latest %}
         <div>
             <h5>Review was not against the latest version:</h5>
diff --git a/opentech/apply/review/tests/factories/blocks.py b/opentech/apply/review/tests/factories/blocks.py
index 31d6290a9dd01a88fdffd2cc908d7733fc926e0f..23ce783dc3b683457666799745928082e7828dad 100644
--- a/opentech/apply/review/tests/factories/blocks.py
+++ b/opentech/apply/review/tests/factories/blocks.py
@@ -3,7 +3,7 @@ import random
 import factory
 
 from opentech.apply.review import blocks
-from opentech.apply.review.options import YES, MAYBE, NO
+from opentech.apply.review.options import YES, MAYBE, NO, PRIVATE, REVIEWER
 from opentech.apply.stream_forms.testing.factories import FormFieldBlockFactory, CharFieldBlockFactory, \
     StreamFieldUUIDFactory
 from opentech.apply.utils.testing.factories import RichTextFieldBlockFactory
@@ -25,6 +25,15 @@ class RecommendationCommentsBlockFactory(FormFieldBlockFactory):
         model = blocks.RecommendationCommentsBlock
 
 
+class VisibilityBlockFactory(FormFieldBlockFactory):
+    class Meta:
+        model = blocks.VisibilityBlock
+
+    @classmethod
+    def make_answer(cls, params=dict()):
+        return random.choices([PRIVATE, REVIEWER])
+
+
 class ScoreFieldBlockFactory(FormFieldBlockFactory):
     class Meta:
         model = blocks.ScoreFieldBlock
@@ -49,4 +58,5 @@ ReviewFormFieldsFactory = StreamFieldUUIDFactory({
     'score': ScoreFieldBlockFactory,
     'recommendation': RecommendationBlockFactory,
     'comments': RecommendationCommentsBlockFactory,
+    'visibility': VisibilityBlockFactory,
 })
diff --git a/opentech/apply/review/tests/factories/models.py b/opentech/apply/review/tests/factories/models.py
index a6d825394a52951c3a37d9e2d409e8da67916c58..59dd321eef691091c99220f0dd02aaad495af969 100644
--- a/opentech/apply/review/tests/factories/models.py
+++ b/opentech/apply/review/tests/factories/models.py
@@ -4,7 +4,7 @@ from opentech.apply.funds.tests.factories import ApplicationSubmissionFactory
 from opentech.apply.stream_forms.testing.factories import FormDataFactory
 from opentech.apply.users.tests.factories import StaffFactory
 
-from ...options import YES, NO, MAYBE, AGREE, DISAGREE
+from ...options import YES, NO, MAYBE, AGREE, DISAGREE, PRIVATE, REVIEWER
 from ...models import Review, ReviewForm, ReviewOpinion
 
 from . import blocks
@@ -24,6 +24,8 @@ class ReviewFactory(factory.DjangoModelFactory):
         recommendation_yes = factory.Trait(recommendation=YES)
         recommendation_maybe = factory.Trait(recommendation=MAYBE)
         draft = factory.Trait(is_draft=True)
+        visibility_private = factory.Trait(visibility=PRIVATE)
+        visibility_reviewer = factory.Trait(visibility=REVIEWER)
 
     submission = factory.SubFactory(ApplicationSubmissionFactory)
     revision = factory.SelfAttribute('submission.live_revision')
diff --git a/opentech/apply/review/tests/test_views.py b/opentech/apply/review/tests/test_views.py
index ed32e84727f9d039324c24b26f0b757768425fe2..1a9bfbe7a23df848adff5f77ba40dd05aeb70ae9 100644
--- a/opentech/apply/review/tests/test_views.py
+++ b/opentech/apply/review/tests/test_views.py
@@ -2,7 +2,7 @@ from django.urls import reverse
 
 from opentech.apply.activity.models import Activity
 from opentech.apply.funds.tests.factories.models import ApplicationSubmissionFactory
-from opentech.apply.users.tests.factories import StaffFactory, UserFactory
+from opentech.apply.users.tests.factories import ReviewerFactory, StaffFactory, UserFactory
 from opentech.apply.utils.testing.tests import BaseViewTestCase
 
 from .factories import ReviewFactory, ReviewFormFieldsFactory, ReviewFormFactory, ReviewOpinionFactory
@@ -296,3 +296,26 @@ class NonStaffReviewOpinionCase(BaseViewTestCase):
         review = ReviewFactory(submission=self.submission, author=staff, recommendation_yes=True)
         response = self.post_page(review, {'agree': AGREE})
         self.assertEqual(response.status_code, 403)
+
+
+class ReviewDetailVisibilityTestCase(BaseViewTestCase):
+    user_factory = ReviewerFactory
+    url_name = 'funds:submissions:reviews:{}'
+    base_view_name = 'review'
+
+    def get_kwargs(self, instance):
+        return {'pk': instance.id, 'submission_pk': instance.submission.id}
+
+    def test_review_detail_visibility_private(self):
+        submission = ApplicationSubmissionFactory(status='external_review', workflow_stages=2)
+        review = ReviewFactory(submission=submission, author=self.user, visibility_private=True)
+        self.client.force_login(self.user_factory())
+        response = self.get_page(review)
+        self.assertEqual(response.status_code, 403)
+
+    def test_review_detail_visibility_reviewer(self):
+        submission = ApplicationSubmissionFactory(status='external_review', workflow_stages=2)
+        review = ReviewFactory(submission=submission, author=self.user, visibility_reviewer=True)
+        self.client.force_login(self.user_factory())
+        response = self.get_page(review)
+        self.assertEqual(response.status_code, 200)
diff --git a/opentech/apply/review/views.py b/opentech/apply/review/views.py
index b73244785370b8f037bbb58743b6c3aa6df1bf65..611de4fb3398ba59b499b54e073316a0b65cca47 100644
--- a/opentech/apply/review/views.py
+++ b/opentech/apply/review/views.py
@@ -169,9 +169,10 @@ class ReviewDisplay(DetailView):
 
     def dispatch(self, request, *args, **kwargs):
         review = self.get_object()
+        user = request.user
         author = review.author
 
-        if request.user != author and not request.user.is_superuser and not request.user.is_apply_staff:
+        if user != author and not (user.is_reviewer and review.reviewer_visibility) and not user.is_apply_staff:
             raise PermissionDenied
 
         if review.is_draft:
diff --git a/opentech/public/forms/models.py b/opentech/public/forms/models.py
index 0e9824c684d14dd7d622f46a380c2b05f42d5fac..bee7352c4805565b82b2193cdf43987aa87c8c69 100644
--- a/opentech/public/forms/models.py
+++ b/opentech/public/forms/models.py
@@ -6,7 +6,9 @@ from django.core.serializers.json import DjangoJSONEncoder
 from django.conf import settings
 from django.db import models
 from django.forms import FileField
+from django.utils.decorators import method_decorator
 from django.utils.translation import ugettext_lazy as _
+from django.views.decorators.cache import never_cache
 
 from modelcluster.fields import ParentalKey
 
@@ -40,6 +42,7 @@ class ExtendedFormBuilder(FormBuilder):
         return FileField(**options)
 
 
+@method_decorator(never_cache, name='serve')
 class FormPage(AbstractEmailForm, BasePage):
     form_builder = ExtendedFormBuilder
     subpage_types = []