diff --git a/apps/packages/helpers/specfile.py b/apps/packages/helpers/specfile.py
index 5430f14e9a6a42748b690fb5c8955cd4ca321610..680f0cd7b7b6e0e6490378e6798235f57f647f63 100644
--- a/apps/packages/helpers/specfile.py
+++ b/apps/packages/helpers/specfile.py
@@ -174,6 +174,28 @@ class PackageSpecFile:
         #     self.spec.specfile_content, escaping=False
         # )
 
+    def get_data(self) -> PackageSpecFileModel or HttpResponse:
+        # get source package specfile
+        self.get_package_specfile()
+
+        # get link for download specfile
+        self.link_for_download()
+
+        # download specfile
+        if self.kwargs.name_down:
+            return self.base, self.download_specfile()
+
+        # add syntax highlighter
+        self.change_specfile_format()
+        return self.spec
+
+    def get_base(self) -> PackageModel:
+        self.base.headline = _("Package %(name)s: Specfile") % {
+            "name": self.kwargs.name
+        }
+        self.base.title = "%(name)s - Specfile" % {"name": self.kwargs.name}
+        return self.base
+
     def get(self) -> tuple[PackageModel, PackageSpecFileModel or HttpResponse]:
         # get source package specfile
         self.get_package_specfile()
diff --git a/apps/packages/views.py b/apps/packages/views.py
index f695e232b8a4e312ad79d86d6e2fcdfe1b21a614..727971b7b0af9b135ba719cfffe0ab7dfb85d91e 100644
--- a/apps/packages/views.py
+++ b/apps/packages/views.py
@@ -210,14 +210,31 @@ class PackageSpecFileView(TemplateView, BasePackageMixin):
     verbose_name = _("Package specfile")
     template_name = "packages/pkg_specfile.html"
     helper_class = PackageSpecFile
-    is_cache = True
+    is_cache = False
     cache_ttl = datetime.timedelta(hours=2)
 
     def get(self, request, *args, **kwargs):
-        response = super().get(request, *args, **kwargs)
-        if isinstance(self.data, HttpResponse):
-            return self.data
-        return response
+        try:
+            context = self.get_context_data(**kwargs)
+        except ApiRequestError as exc:
+            if exc.dErrorCode >= 500:
+                return render(self.request, "errors/500.html", status=500)
+            else:
+                return render(self.request, "errors/404.html", status=404)
+        return self.render_to_response(context)
+
+    def get_context_data(self, **kwargs):
+        app_names = self.request.resolver_match.app_names
+        self.base = PackageSpecFile(self.kwargs, app_names).get_base()
+        context = super().get_context_data(**kwargs)
+        context["base"] = self.base
+        if check_captcha(self.request):
+            try:
+                self.data = PackageSpecFile(self.kwargs, app_names).get_data()
+            except ApiRequestError:
+                self.data = {}
+            context["data"] = self.data
+        return context
 
 
 class PackageRepocopView(BasePackageMixin, CustomListView):
diff --git a/templates/packages/pkg_specfile.html b/templates/packages/pkg_specfile.html
index cf8108fb4f6fe8159eb983603bfdd69ac12cc917..c84d9b4f8b61a5f32e976b5026ea6ad8a9b447fd 100644
--- a/templates/packages/pkg_specfile.html
+++ b/templates/packages/pkg_specfile.html
@@ -4,6 +4,10 @@
 {% block style %}
     <link rel="stylesheet" href="{% static 'main/css/pygments.css' %}" type="text/css">
     <link rel="stylesheet" href="{% static 'main/css/jquery.floatingscroll.css' %}" type="text/css">
+    <script nonce="{{ CSP_NONCE }}"
+      src="https://smartcaptcha.yandexcloud.net/captcha.js?render=onload&onload=onloadFunction"
+      defer
+    ></script>
 {% endblock %}
 
 {% block meta %}
@@ -12,16 +16,44 @@
 {% endblock %}
 
 {% block info %}
+    <form id="captcha-form" method="POST">{% csrf_token %}
+        <div id="captcha-container"></div>
+    </form>
+
     <section class="pf-c-page__main-section pf-m-no-padding pf-m-fill">
-        <div class="pf-c-page__main-body">
+        <div class="pf-c-page__main-body" id="specfile__main-body">
+            {% if not data %}
+                <div class="pf-c-card pf-m-expanded" id="card-action-no-offset">
+                    {% include "include/empty_state.html" %}
+                </div>
+            {% else %}
+            <div class="pf-c-card">
+                <div class="pf-c-card__body">
+                    <div role="presentation" class="pf-m-loading pf-u-text-align-center" id="preloader" style="display: none;">
+                        <span class="pf-c-spinner pf-m-xl" role="progressbar" aria-label="Loading items">
+                            <span class="pf-c-spinner__clipper"></span>
+                            <span class="pf-c-spinner__lead-ball"></span>
+                            <span class="pf-c-spinner__tail-ball"></span>
+                        </span>
+                    </div>
+                    <noscript>
+                        <div aria-label="Danger alert" class="pf-c-alert pf-m-danger">
+                            <div class="pf-c-alert__icon">
+                                <i class="fas fa-fw fa-exclamation-circle" aria-hidden="true"></i>
+                            </div>
+                            <p class="pf-c-alert__title">{% trans "JavaScript must be enabled to display the specfile." %}</p>
+                        </div>
+                    </noscript>
+                </div>
+            </div>
             <div class="pf-c-panel">
               <div class="pf-c-panel__main">
                 <div class="pf-c-panel__main-body pf-u-p-0" style="overflow: auto;">
                         {{ data.specfile_content|convert_vulns_to_link:False }}
                 </div>
-
               </div>
             </div>
+            {% endif %}
         </div>
     </section>
 {% endblock %}
@@ -29,4 +61,54 @@
 {% block js %}
     <script nonce="{{ CSP_NONCE }}" src="{% static 'main/js/jquery.floatingscroll.min.js' %}"></script>
     <script nonce="{{ CSP_NONCE }}" type="module" src="{% static 'main/js/specfile.js' %}?{% static_version %}"></script>
+
+    <script nonce="{{ CSP_NONCE }}">
+
+        function onloadFunction() {
+            if (!window.smartCaptcha) {
+                return;
+            }
+
+            window.smartCaptcha.render('captcha-container', {
+                sitekey: 'ysc1_GKOeeURc7dvgU8750mmFWyePhkMh7fyISle1qbMifa080da5',
+                invisible: true,
+                callback: callback,
+            });
+        }
+
+        function callback(token) {
+            console.log("asd")
+            $.ajax({
+                data: $("#captcha-form").serialize(),
+                url: "",
+                type: "GET",
+                beforeSend: function () {
+                    $('#preloader').show();
+                },
+                complete: function() {
+                    $('#preloader').hide();
+                },
+                success: (data) => {
+                    const $html = $(data);
+                    console.log($html)
+                    const $element = $html.find('#specfile__main-body');
+                    $('#specfile__main-body').empty().append( $($element).html());
+                },
+                error: (exc) => {
+                    if (exc.status === 404) {
+                        $("#specfile__main-body").append(exc.responseText)
+                    }
+                }
+            });
+        }
+
+        function handleSubmit() {
+            if (!window.smartCaptcha) {
+                return;
+            }
+
+            window.smartCaptcha.execute();
+        }
+        window.onload = handleSubmit;
+    </script>
 {% endblock %}