diff --git a/edge-apps/klipfolio-power-metrics-dashboard/index.html b/edge-apps/klipfolio-power-metrics-dashboard/index.html
new file mode 100644
index 000000000..68fa6bc7a
--- /dev/null
+++ b/edge-apps/klipfolio-power-metrics-dashboard/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Klipfolio Dashboard
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/edge-apps/klipfolio-power-metrics-dashboard/instance.yml b/edge-apps/klipfolio-power-metrics-dashboard/instance.yml
new file mode 100644
index 000000000..174606c39
--- /dev/null
+++ b/edge-apps/klipfolio-power-metrics-dashboard/instance.yml
@@ -0,0 +1,4 @@
+---
+syntax: instance_v1
+id: 01JT3644XKZ7BWNVY1ZQXTW4AG
+name: Klipfolio Dashboard Edge App
diff --git a/edge-apps/klipfolio-power-metrics-dashboard/screenly.yml b/edge-apps/klipfolio-power-metrics-dashboard/screenly.yml
new file mode 100644
index 000000000..6f96825bd
--- /dev/null
+++ b/edge-apps/klipfolio-power-metrics-dashboard/screenly.yml
@@ -0,0 +1,15 @@
+---
+syntax: manifest_v1
+id: 01JSR8A2CW98PG8B0SR3T0MYX5
+description: A Klipfolio dashboard edge app for Screenly
+settings:
+ dashboard_url:
+ type: string
+ title: Dashboard URL
+ optional: true
+ help_text: The URL for the dashboard
+ dashboard_passcode:
+ type: secret
+ title: Dashboard Passcode
+ optional: true
+ help_text: The passcode for the dashboard
\ No newline at end of file
diff --git a/edge-apps/klipfolio-power-metrics-dashboard/script.js b/edge-apps/klipfolio-power-metrics-dashboard/script.js
new file mode 100644
index 000000000..642b5b177
--- /dev/null
+++ b/edge-apps/klipfolio-power-metrics-dashboard/script.js
@@ -0,0 +1,68 @@
+ /* global screenly, Sentry */
+/* eslint-disable-next-line no-unused-vars, no-useless-catch */
+
+ const dashboardUrlRaw = screenly.settings.dashboard_url || 'Dashboard URL not set'
+ const passcode = screenly.settings.dashboard_passcode || 'Passcode not set'
+
+// Initialize when page loads
+window.addEventListener('load', function() {
+ // Wait a short time for screenly.js to load
+ setTimeout(function() {
+ // Get the dashboard iframe
+ const dashboard = document.getElementById('dashboard')
+
+ // Construct the URL after screenly.js has loaded
+ let dashboardUrl
+ try {
+ // Try to use Screenly's CORS proxy
+ dashboardUrl = screenly.cors_proxy_url + encodeURIComponent(dashboardUrlRaw)
+ } catch (e) {
+ // Fallback to direct URL if screenly is not available
+ console.error("Error accessing screenly.cors_proxy_url, using direct URL", e)
+ dashboardUrl = dashboardUrlRaw;
+ }
+
+ // Set dashboard URL
+ dashboard.src = dashboardUrl
+
+ // Attempt to inject passcode after iframe loads
+ dashboard.onload = function() {
+ setTimeout(injectPasscodeIntoIframe, 1000)
+ };
+ }, 500) // 500ms delay for screenly.js to load
+});
+
+// Function to inject passcode into iframe
+function injectPasscodeIntoIframe() {
+ try {
+ const iframe = document.getElementById('dashboard')
+
+ // Try to access the iframe document
+ let iframeDoc;
+ try {
+ iframeDoc = iframe.contentDocument || iframe.contentWindow.document
+ } catch (e) {
+ console.error("Cannot access iframe content due to cross-origin restrictions", e)
+ return
+ }
+
+ // Get passcode input
+ const input = iframeDoc.getElementById('passcode')
+
+ // If passcode input exists, inject passcode and submit
+ if (input) {
+ console.log("Found passcode field, injecting code");
+ input.value = passcode
+ input.dispatchEvent(new Event('input', { bubbles: true }))
+
+ // Get the submit button and click it
+ const button = iframeDoc.getElementById('submit')
+ button.click()
+ console.log("Clicked submit button")
+ } else {
+ console.log("Passcode input field not found");
+ }
+ } catch (e) {
+ console.error("Error in injectPasscodeIntoIframe:", e)
+ }
+}
\ No newline at end of file
diff --git a/edge-apps/klipfolio-power-metrics-dashboard/styles.css b/edge-apps/klipfolio-power-metrics-dashboard/styles.css
new file mode 100644
index 000000000..7ed698dcf
--- /dev/null
+++ b/edge-apps/klipfolio-power-metrics-dashboard/styles.css
@@ -0,0 +1,17 @@
+/* This file is no longer needed as all styles are defined in the HTML */
+/* The file is kept for reference in case styles need to be extracted later */
+
+body, html {
+ margin: 0;
+ padding: 0;
+ width: 100%;
+ height: 100%;
+ overflow: hidden;
+}
+
+#dashboard {
+ width: 100%;
+ height: 100%;
+ border: none;
+ display: block;
+}
\ No newline at end of file