diff --git a/README.md b/README.md
index 9f17e98..043a831 100644
--- a/README.md
+++ b/README.md
@@ -26,6 +26,7 @@ community Recipes:
- [Parcel](/lib/parcel)
- [RSS Feed](/lib/rss_feed)
- [Shopify](/lib/shopify)
+- [Statuspage](/lib/statuspage)
- [Stock Price](/lib/stock_price)
- [Tempest Weather Station](/lib/tempest_weather_station)
- [Todoist](/lib/todoist)
diff --git a/lib/statuspage/statuspage.rb b/lib/statuspage/statuspage.rb
new file mode 100644
index 0000000..028784a
--- /dev/null
+++ b/lib/statuspage/statuspage.rb
@@ -0,0 +1,83 @@
+module Plugins
+ class Statuspage < Base
+
+ def locals
+ { pages: }
+ end
+
+ private
+
+ # NOTE: only works with pages hosted on statuspage.io
+ def pages
+ content = { 'incidents' => [], 'scheduled' => [] }
+ items.each do |item|
+ next unless item.is_a?(Hash) && item[:date]
+
+ if item[:date] > DateTime.now
+ item[:icon] = 'calendar_star'
+ content['scheduled'] << item
+ else
+ item[:icon] = item[:date] > 24.hours.ago ? 'shield_warning' : 'hexagon'
+ content['incidents'] << item
+ end
+ end
+
+ content
+ end
+
+ # rubocop:disable Security/Open
+ def items
+ page_urls.map do |url|
+ URI.open(url, open_timeout: 5) do |rss|
+ feed = RSS::Parser.parse(rss, validate: false)
+ latest_post = feed&.items&.first
+
+ if latest_post.nil?
+ {
+ content: 'Unsupported status page',
+ site_name: url
+ }
+ elsif latest_post.is_a?(RSS::Atom::Feed::Entry)
+ {
+ title: latest_post&.title&.content,
+ date: latest_post&.published&.content,
+ content: latest_post&.content&.content,
+ site_name: feed&.title&.content
+ }
+ else
+ {
+ title: latest_post&.title,
+ date: latest_post&.pubDate,
+ content: latest_post&.description, # not used, just in case
+ site_name: feed&.channel&.title&.split('Status')&.first&.squish # => 'Prompt.io'
+ }
+ end
+ end
+ rescue OpenURI::HTTPError, RSS::NotWellFormedError, Errno::ENOENT
+ nil
+ rescue URI::InvalidURIError, SocketError, Resolv::ResolvError, Net::OpenTimeout, Net::ReadTimeout,
+ OpenSSL::SSL::SSLError, Errno::EHOSTUNREACH, Errno::ECONNREFUSED, Errno::EPIPE => e
+ handle_erroring_state(e.message)
+ nil
+ rescue RuntimeError => e
+ raise unless e.message.include?('redirection forbidden')
+
+ handle_erroring_state(e.message)
+ nil
+ end.compact
+ end
+ # rubocop:enable Security/Open
+
+ def page_urls
+ line_separated_string_to_array(settings['page_urls']).map do |base_url|
+ next unless base_url.include?('http') # IDEA: extract RssFeed > validate_uri()
+
+ if ['/history.rss', '/feed'].any? { |pattern| base_url.include?(pattern) }
+ base_url
+ else
+ base_url.chomp('/').concat('/history.rss')
+ end
+ end.compact # ignores skipped / malformed URLs
+ end
+ end
+end
diff --git a/lib/statuspage/views/full.html.erb b/lib/statuspage/views/full.html.erb
new file mode 100644
index 0000000..6ced291
--- /dev/null
+++ b/lib/statuspage/views/full.html.erb
@@ -0,0 +1,5 @@
+
+ <%= render "plugins/statuspage/shared/layout", pages: pages, always_columns: true, overflow_counter: true, large_text: true %>
+
+ <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %>
+
diff --git a/lib/statuspage/views/half_horizontal.html.erb b/lib/statuspage/views/half_horizontal.html.erb
new file mode 100644
index 0000000..bcc1853
--- /dev/null
+++ b/lib/statuspage/views/half_horizontal.html.erb
@@ -0,0 +1,5 @@
+
+ <%= render "plugins/statuspage/shared/layout", pages: pages, clamp_details: true, always_columns: true %>
+
+ <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %>
+
diff --git a/lib/statuspage/views/half_vertical.html.erb b/lib/statuspage/views/half_vertical.html.erb
new file mode 100644
index 0000000..33bdbdb
--- /dev/null
+++ b/lib/statuspage/views/half_vertical.html.erb
@@ -0,0 +1,5 @@
+
+ <%= render "plugins/statuspage/shared/layout", pages: pages, overflow_counter: true %>
+
+ <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %>
+
diff --git a/lib/statuspage/views/quadrant.html.erb b/lib/statuspage/views/quadrant.html.erb
new file mode 100644
index 0000000..908ca3f
--- /dev/null
+++ b/lib/statuspage/views/quadrant.html.erb
@@ -0,0 +1,5 @@
+
+ <%= render "plugins/statuspage/shared/layout", pages: pages %>
+
+ <%= render "plugins/statuspage/shared/title_bar", instance_name: instance_name %>
+
diff --git a/lib/statuspage/views/shared/_calendar_star.html.erb b/lib/statuspage/views/shared/_calendar_star.html.erb
new file mode 100644
index 0000000..88f4c78
--- /dev/null
+++ b/lib/statuspage/views/shared/_calendar_star.html.erb
@@ -0,0 +1 @@
+
diff --git a/lib/statuspage/views/shared/_hexagon.html.erb b/lib/statuspage/views/shared/_hexagon.html.erb
new file mode 100644
index 0000000..410d9c8
--- /dev/null
+++ b/lib/statuspage/views/shared/_hexagon.html.erb
@@ -0,0 +1 @@
+
diff --git a/lib/statuspage/views/shared/_layout.html.erb b/lib/statuspage/views/shared/_layout.html.erb
new file mode 100644
index 0000000..0dd3e49
--- /dev/null
+++ b/lib/statuspage/views/shared/_layout.html.erb
@@ -0,0 +1,44 @@
+<% groups = (pages || {}).to_a.first(2) %>
+<% always_columns = local_assigns[:always_columns] == true %>
+<% large_text = local_assigns[:large_text] == true %>
+<% heading_label_class = large_text ? "label lg:label--large" : "label" %>
+<% title_class = large_text ? "title title--small lg:title--base" : "title title--small" %>
+
+
+
+ <% groups.each_with_index do |(type, items), index| %>
+ <% section_items = Array(items) %>
+
+
+
+ <%= type.to_s.titleize %>
+
+
+
+
+ <% section_items.each do |item| %>
+
+
+
+
+ <%= render "plugins/statuspage/shared/#{item[:icon]}", classes: (local_assigns[:icon_classes] || "w--6 h--6") %>
+ <%= item[:site_name] %>
+
+
data-clamp="1"<% end %>>
+ <% if type.to_s == 'scheduled' %>
+ Scheduled: <%= l(item[:date].to_date, format: "%B %d, %Y") %>
+ <% elsif type.to_s == 'incidents' %>
+ Last Incident: <%= localized_time_ago(item[:date]) %>
+ <% end %>
+
+
data-clamp="1"<% end %>><%= item[:title] %>
+
+
+ <% end %>
+
+
+
+
+ <% end %>
+
+
diff --git a/lib/statuspage/views/shared/_shield_warning.html.erb b/lib/statuspage/views/shared/_shield_warning.html.erb
new file mode 100644
index 0000000..59c7358
--- /dev/null
+++ b/lib/statuspage/views/shared/_shield_warning.html.erb
@@ -0,0 +1 @@
+
diff --git a/lib/statuspage/views/shared/_title_bar.html.erb b/lib/statuspage/views/shared/_title_bar.html.erb
new file mode 100644
index 0000000..5939e98
--- /dev/null
+++ b/lib/statuspage/views/shared/_title_bar.html.erb
@@ -0,0 +1,5 @@
+
+ <%= image_tag plugin_image_path("statuspage--render.svg"), class: "image image--adaptive", alt: "Statuspage" %>
+
Statuspage
+ <%= instance_name %>
+