screenshotapi_to 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c1c1d419da719dd316e4191a2e504bacc39397c41c9e88a2c65f3208f72a4f3d
4
+ data.tar.gz: 2ee900fd3711e56949e0c5d77beacf600bed5662341b5293123a059e18305bf2
5
+ SHA512:
6
+ metadata.gz: 31f16655ac4f7c5211fc7d6adf0a1d2b94b9f1423f321597ff8e8b0da8ccf352922d78e2799214e96c054f228cd044cd61f705eef04fd7705f31f22c7fd8f227
7
+ data.tar.gz: 8690139a987d24acb4f4b77f43f2f547212e8180a5557309c2d00dcc59dd06a334f1de3b9440e68b83af028bb2c88bf7dbc93de95f8d0b73d033b32d3533ab3b
data/CHANGELOG.md ADDED
@@ -0,0 +1,6 @@
1
+ # Changelog
2
+
3
+ ## 1.0.0
4
+
5
+ - Initial Ruby SDK release for ScreenshotAPI.
6
+ - Supports screenshot capture, saving to disk, metadata headers, typed API errors, and advanced GET options.
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ScreenshotAPI
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,230 @@
1
+ # screenshotapi_to
2
+
3
+ Official Ruby SDK for [ScreenshotAPI](https://screenshotapi.to?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk). Capture website screenshots, PDFs, and rendered page states with a small `net/http` client and no runtime dependencies.
4
+
5
+ ## Installation
6
+
7
+ Add the gem to your Gemfile:
8
+
9
+ ```ruby
10
+ gem "screenshotapi_to", require: "screenshotapi"
11
+ ```
12
+
13
+ Then install:
14
+
15
+ ```bash
16
+ bundle install
17
+ ```
18
+
19
+ Or install directly:
20
+
21
+ ```bash
22
+ gem install screenshotapi_to
23
+ ```
24
+
25
+ ## Authentication
26
+
27
+ Create a free ScreenshotAPI account and copy an API key from the dashboard:
28
+
29
+ - [Get an API key](https://screenshotapi.to/sign-up?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
30
+ - [API documentation](https://screenshotapi.to/docs?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
31
+
32
+ Keep the key on the server and load it from an environment variable:
33
+
34
+ ```bash
35
+ export SCREENSHOTAPI_KEY="sk_live_your_key_here"
36
+ ```
37
+
38
+ ```ruby
39
+ require "screenshotapi"
40
+
41
+ client = ScreenshotAPI::Client.new(ENV.fetch("SCREENSHOTAPI_KEY"))
42
+ ```
43
+
44
+ ## First Screenshot
45
+
46
+ Capture a PNG and save it to disk:
47
+
48
+ ```ruby
49
+ require "screenshotapi"
50
+
51
+ client = ScreenshotAPI::Client.new(ENV.fetch("SCREENSHOTAPI_KEY"))
52
+
53
+ metadata = client.save(
54
+ url: "https://example.com",
55
+ path: "screenshot.png"
56
+ )
57
+
58
+ puts "Screenshot ID: #{metadata.screenshot_id}"
59
+ puts "Credits remaining: #{metadata.credits_remaining}"
60
+ ```
61
+
62
+ Use `screenshot` when you need the raw bytes:
63
+
64
+ ```ruby
65
+ result = client.screenshot(url: "https://example.com", type: "webp")
66
+
67
+ File.binwrite("screenshot.webp", result.image)
68
+ puts result.content_type
69
+ puts result.metadata.duration_ms
70
+ ```
71
+
72
+ ## Advanced Options
73
+
74
+ All GET-compatible screenshot options can be passed as Ruby keyword arguments. The client converts snake_case keys to ScreenshotAPI query parameters.
75
+
76
+ ```ruby
77
+ result = client.screenshot(
78
+ url: "https://example.com/pricing",
79
+ width: 1440,
80
+ height: 1200,
81
+ full_page: true,
82
+ type: "webp",
83
+ quality: 85,
84
+ color_scheme: "dark",
85
+ wait_until: "networkidle2",
86
+ wait_for_selector: "main",
87
+ delay: 500,
88
+ block_ads: true,
89
+ remove_cookie_banners: true,
90
+ stealth_mode: true,
91
+ device_pixel_ratio: 2,
92
+ timezone: "America/New_York",
93
+ locale: "en-US",
94
+ cache_ttl: 300,
95
+ preload_fonts: true,
96
+ remove_elements: [".newsletter", "#cookie-banner"],
97
+ remove_popups: true
98
+ )
99
+
100
+ File.binwrite("pricing.webp", result.image)
101
+ ```
102
+
103
+ Render raw HTML with `html:`. This uses `POST /api/v1/screenshot` with a JSON body:
104
+
105
+ ```ruby
106
+ result = client.screenshot(
107
+ html: "<main><h1>Hello from Ruby</h1></main>",
108
+ width: 800,
109
+ height: 600,
110
+ type: "png"
111
+ )
112
+ ```
113
+
114
+ Generate a PDF:
115
+
116
+ ```ruby
117
+ metadata = client.save(
118
+ url: "https://example.com/report",
119
+ type: "pdf",
120
+ path: "report.pdf"
121
+ )
122
+ ```
123
+
124
+ ## API Reference
125
+
126
+ ### `ScreenshotAPI::Client.new(api_key, base_url:, timeout:)`
127
+
128
+ | Parameter | Type | Required | Default | Description |
129
+ | --- | --- | --- | --- | --- |
130
+ | `api_key` | `String` | Yes | - | Your ScreenshotAPI key. |
131
+ | `base_url` | `String` | No | `https://screenshotapi.to` | API base URL. |
132
+ | `timeout` | `Integer` | No | `60` | Open and read timeout in seconds. |
133
+
134
+ ### `client.screenshot(**options)`
135
+
136
+ Returns `ScreenshotAPI::Result`.
137
+
138
+ | Option | Type | Required | Default | Description |
139
+ | --- | --- | --- | --- | --- |
140
+ | `url` | `String` | Yes, unless `html` is provided | - | Absolute `http` or `https` URL to capture. |
141
+ | `html` | `String` | No | - | Raw HTML to render. Uses POST. |
142
+ | `width` | `Integer` | No | `1440` | Viewport width in pixels. |
143
+ | `height` | `Integer` | No | `900` | Viewport height in pixels. |
144
+ | `full_page` | `Boolean` | No | `false` | Capture the full scrollable page. |
145
+ | `type` | `String` | No | `"png"` | `"png"`, `"jpeg"`, `"webp"`, or `"pdf"`. |
146
+ | `quality` | `Integer` | No | `100` | JPEG/WebP quality from `1` to `100`. |
147
+ | `color_scheme` | `String` | No | - | `"light"` or `"dark"`. |
148
+ | `wait_until` | `String` | No | `"networkidle2"` | `"load"`, `"domcontentloaded"`, `"networkidle0"`, or `"networkidle2"`. |
149
+ | `wait_for_selector` | `String` | No | - | CSS selector to wait for before capture. |
150
+ | `delay` | `Integer` | No | `0` | Additional delay in milliseconds. |
151
+ | `block_ads` | `Boolean` | No | `false` | Remove ads before capture. |
152
+ | `remove_cookie_banners` | `Boolean` | No | `false` | Auto-remove common cookie consent dialogs. |
153
+ | `css_inject` | `String` | No | - | CSS to inject before capture. |
154
+ | `js_inject` | `String` | No | - | JavaScript to run before capture. |
155
+ | `stealth_mode` | `Boolean` | No | `false` | Enable anti-bot-detection mode. |
156
+ | `device_pixel_ratio` | `Integer` | No | `1` | Retina/HiDPI scale. Accepted values: `1`, `2`, `3`. |
157
+ | `timezone` | `String` | No | - | IANA timezone, such as `"America/New_York"`. |
158
+ | `locale` | `String` | No | - | BCP 47 locale, such as `"en-US"`. |
159
+ | `cache_ttl` | `Integer` | No | `0` | Response cache TTL in seconds. |
160
+ | `preload_fonts` | `Boolean` | No | `false` | Preload discovered Google Fonts before capture. |
161
+ | `remove_elements` | `Array<String>` | No | - | CSS selectors to remove before capture. |
162
+ | `remove_popups` | `Boolean` | No | `false` | Remove common popups and overlays. |
163
+ | `mockup_device` | `String` | No | - | `"browser"`, `"iphone"`, or `"macbook"`. |
164
+ | `geo_latitude`, `geo_longitude`, `geo_accuracy` | `Number` | No | - | Browser geolocation override for GET requests. |
165
+
166
+ ### `client.save(path:, **options)`
167
+
168
+ Same options as `screenshot`, plus `path:`. Writes the response body to disk and returns `ScreenshotAPI::Metadata`.
169
+
170
+ ## Error Handling
171
+
172
+ The SDK raises typed errors for API responses and network failures:
173
+
174
+ ```ruby
175
+ require "screenshotapi"
176
+
177
+ client = ScreenshotAPI::Client.new(ENV.fetch("SCREENSHOTAPI_KEY"))
178
+
179
+ begin
180
+ result = client.screenshot(url: "https://example.com")
181
+ File.binwrite("screenshot.png", result.image)
182
+ rescue ScreenshotAPI::AuthenticationError
183
+ warn "API key missing or malformed"
184
+ rescue ScreenshotAPI::InvalidAPIKeyError
185
+ warn "API key revoked or invalid"
186
+ rescue ScreenshotAPI::InsufficientCreditsError => e
187
+ warn "No credits remaining. Balance: #{e.balance}"
188
+ rescue ScreenshotAPI::ScreenshotFailedError => e
189
+ warn "Screenshot capture failed: #{e.message}"
190
+ rescue ScreenshotAPI::NetworkError => e
191
+ warn "Network error: #{e.message}"
192
+ rescue ScreenshotAPI::APIError => e
193
+ warn "ScreenshotAPI error #{e.status}: #{e.message}"
194
+ end
195
+ ```
196
+
197
+ ## Examples
198
+
199
+ Runnable examples live in `examples/`:
200
+
201
+ - `examples/plain_ruby.rb` captures a screenshot from a plain Ruby script.
202
+ - `examples/rails_controller.rb` shows a Rails controller action that returns screenshot bytes with typed error responses.
203
+
204
+ Run the plain Ruby example with:
205
+
206
+ ```bash
207
+ SCREENSHOTAPI_KEY="sk_live_your_key_here" ruby examples/plain_ruby.rb
208
+ ```
209
+
210
+ ## Pricing And Free Tier
211
+
212
+ New accounts include 200 free screenshots per month. Paid plans support higher monthly volume, credit packs, caching, webhooks, S3 upload, signed URLs, and priority support.
213
+
214
+ - [Start free](https://screenshotapi.to/sign-up?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
215
+ - [View pricing](https://screenshotapi.to/pricing?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
216
+
217
+ ## Documentation And Support
218
+
219
+ - [Ruby SDK documentation](https://screenshotapi.to/docs/sdks/ruby?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
220
+ - [Screenshot API reference](https://screenshotapi.to/docs/api/screenshot?utm_source=ruby_sdk&utm_medium=readme&utm_campaign=sdk&ref=ruby-sdk)
221
+ - [Email support](mailto:support@screenshotapi.to)
222
+
223
+ ## Requirements
224
+
225
+ - Ruby 3.0+
226
+ - No runtime gem dependencies. The client uses `net/http`, `json`, and `uri` from the Ruby standard library.
227
+
228
+ ## License
229
+
230
+ MIT
@@ -0,0 +1,29 @@
1
+ require "screenshotapi"
2
+
3
+ api_key = ENV["SCREENSHOTAPI_KEY"]
4
+ abort "Set SCREENSHOTAPI_KEY before running this example." if api_key.nil? || api_key.strip.empty?
5
+
6
+ client = ScreenshotAPI::Client.new(api_key)
7
+
8
+ begin
9
+ metadata = client.save(
10
+ url: "https://example.com",
11
+ path: "example.png",
12
+ width: 1440,
13
+ height: 900,
14
+ full_page: true,
15
+ type: "png",
16
+ block_ads: true,
17
+ remove_cookie_banners: true
18
+ )
19
+
20
+ puts "Saved example.png"
21
+ puts "Screenshot ID: #{metadata.screenshot_id}"
22
+ puts "Credits remaining: #{metadata.credits_remaining}"
23
+ rescue ScreenshotAPI::InsufficientCreditsError => e
24
+ warn "ScreenshotAPI credits exhausted. Balance: #{e.balance}"
25
+ exit 1
26
+ rescue ScreenshotAPI::APIError => e
27
+ warn "ScreenshotAPI request failed (#{e.code}, HTTP #{e.status || "n/a"}): #{e.message}"
28
+ exit 1
29
+ end
@@ -0,0 +1,35 @@
1
+ require "screenshotapi"
2
+
3
+ class ScreenshotsController < ApplicationController
4
+ def show
5
+ result = screenshot_client.screenshot(
6
+ url: params.require(:url),
7
+ width: params.fetch(:width, 1440).to_i,
8
+ height: params.fetch(:height, 900).to_i,
9
+ type: params.fetch(:type, "png"),
10
+ full_page: ActiveModel::Type::Boolean.new.cast(params[:full_page]),
11
+ block_ads: true,
12
+ remove_cookie_banners: true
13
+ )
14
+
15
+ expires_in 1.hour, public: true
16
+ send_data result.image, type: result.content_type, disposition: "inline"
17
+ rescue ActionController::ParameterMissing
18
+ render json: { error: "url is required" }, status: :bad_request
19
+ rescue ScreenshotAPI::InsufficientCreditsError => e
20
+ render json: { error: "insufficient credits", balance: e.balance }, status: :payment_required
21
+ rescue ScreenshotAPI::AuthenticationError, ScreenshotAPI::InvalidAPIKeyError
22
+ render json: { error: "ScreenshotAPI authentication failed" }, status: :unauthorized
23
+ rescue ScreenshotAPI::APIError => e
24
+ Rails.logger.warn("ScreenshotAPI failed: #{e.code} #{e.message}")
25
+ render json: { error: "screenshot capture failed" }, status: :bad_gateway
26
+ end
27
+
28
+ private
29
+
30
+ def screenshot_client
31
+ @screenshot_client ||= ScreenshotAPI::Client.new(
32
+ Rails.application.credentials.dig(:screenshotapi, :api_key)
33
+ )
34
+ end
35
+ end
@@ -0,0 +1,195 @@
1
+ require "net/http"
2
+ require "uri"
3
+ require "json"
4
+
5
+ module ScreenshotAPI
6
+ class Client
7
+ QUERY_PARAM_MAP = {
8
+ url: "url",
9
+ width: "width",
10
+ height: "height",
11
+ full_page: "fullPage",
12
+ type: "type",
13
+ quality: "quality",
14
+ color_scheme: "colorScheme",
15
+ wait_until: "waitUntil",
16
+ wait_for_selector: "waitForSelector",
17
+ delay: "delay",
18
+ block_ads: "blockAds",
19
+ remove_cookie_banners: "removeCookieBanners",
20
+ css_inject: "cssInject",
21
+ js_inject: "jsInject",
22
+ stealth_mode: "stealthMode",
23
+ device_pixel_ratio: "devicePixelRatio",
24
+ timezone: "timezone",
25
+ locale: "locale",
26
+ cache_ttl: "cacheTtl",
27
+ preload_fonts: "preloadFonts",
28
+ remove_elements: "removeElements",
29
+ remove_popups: "removePopups",
30
+ mockup_device: "mockupDevice",
31
+ geo_latitude: "geoLatitude",
32
+ geo_longitude: "geoLongitude",
33
+ geo_accuracy: "geoAccuracy"
34
+ }.freeze
35
+
36
+ BODY_PARAM_MAP = QUERY_PARAM_MAP.merge(
37
+ html: "html",
38
+ geo_location: "geoLocation"
39
+ ).freeze
40
+
41
+ def initialize(api_key, base_url: DEFAULT_BASE_URL, timeout: DEFAULT_TIMEOUT)
42
+ raise ArgumentError, "API key is required" if blank?(api_key)
43
+
44
+ @api_key = api_key.to_s
45
+ @base_url = normalize_base_url(base_url)
46
+ @timeout = timeout
47
+ end
48
+
49
+ def screenshot(**options)
50
+ validate_capture_target!(options)
51
+
52
+ uri, request = build_request(options)
53
+ request["x-api-key"] = @api_key
54
+
55
+ response = perform_request(uri, request)
56
+
57
+ unless response.is_a?(Net::HTTPSuccess)
58
+ handle_error(response)
59
+ end
60
+
61
+ metadata = Metadata.new(
62
+ credits_remaining: integer_header(response, "x-credits-remaining"),
63
+ screenshot_id: response["x-screenshot-id"] || "",
64
+ duration_ms: integer_header(response, "x-duration-ms")
65
+ )
66
+
67
+ Result.new(
68
+ image: response.body,
69
+ content_type: response["content-type"] || "image/png",
70
+ metadata: metadata
71
+ )
72
+ end
73
+
74
+ def save(path:, **options)
75
+ result = screenshot(**options)
76
+ File.binwrite(path, result.image)
77
+ result.metadata
78
+ end
79
+
80
+ private
81
+
82
+ def perform_request(uri, request)
83
+ http = Net::HTTP.new(uri.host, uri.port)
84
+ http.use_ssl = uri.scheme == "https"
85
+ http.open_timeout = @timeout
86
+ http.read_timeout = @timeout
87
+
88
+ http.request(request)
89
+ rescue Timeout::Error, SocketError, SystemCallError, IOError => e
90
+ raise NetworkError, e.message
91
+ end
92
+
93
+ def build_uri(options)
94
+ params = build_params(options, QUERY_PARAM_MAP)
95
+
96
+ uri = URI("#{@base_url}/api/v1/screenshot")
97
+ uri.query = URI.encode_www_form(params)
98
+ uri
99
+ end
100
+
101
+ def build_request(options)
102
+ if present?(options[:html])
103
+ uri = URI("#{@base_url}/api/v1/screenshot")
104
+ request = Net::HTTP::Post.new(uri)
105
+ request["content-type"] = "application/json"
106
+ request.body = JSON.generate(build_body(options))
107
+ [uri, request]
108
+ else
109
+ uri = build_uri(options)
110
+ [uri, Net::HTTP::Get.new(uri)]
111
+ end
112
+ end
113
+
114
+ def build_body(options)
115
+ build_params(options, BODY_PARAM_MAP, stringify: false)
116
+ end
117
+
118
+ def build_params(options, mapping, stringify: true)
119
+ mapping.each_with_object({}) do |(option_key, param_key), params|
120
+ next unless options.key?(option_key)
121
+
122
+ value = normalize_param_value(option_key, options[option_key], stringify: stringify)
123
+ next if value.nil?
124
+
125
+ params[param_key] = stringify ? value.to_s : value
126
+ end
127
+ end
128
+
129
+ def normalize_param_value(option_key, value, stringify:)
130
+ return nil if value.nil?
131
+ return value.join(",") if stringify && option_key == :remove_elements && value.respond_to?(:join)
132
+
133
+ value
134
+ end
135
+
136
+ def handle_error(response)
137
+ body = parse_error_body(response)
138
+
139
+ message = body["error"] || body["message"] || "HTTP #{response.code}"
140
+
141
+ case response.code.to_i
142
+ when 401
143
+ raise AuthenticationError, message
144
+ when 402
145
+ balance = body.key?("balance") ? body["balance"] : body["creditBalance"]
146
+ raise InsufficientCreditsError.new(message, balance: integer_value(balance))
147
+ when 403
148
+ raise InvalidAPIKeyError, message
149
+ when 500
150
+ raise ScreenshotFailedError, (body["message"] || body["error"] || "Screenshot failed")
151
+ else
152
+ raise APIError.new(message, status: response.code.to_i, code: "unknown_error")
153
+ end
154
+ end
155
+
156
+ def parse_error_body(response)
157
+ parsed = JSON.parse(response.body.to_s)
158
+ parsed.is_a?(Hash) ? parsed : { "error" => "HTTP #{response.code}" }
159
+ rescue JSON::ParserError
160
+ { "error" => "HTTP #{response.code}" }
161
+ end
162
+
163
+ def integer_header(response, header)
164
+ integer_value(response[header])
165
+ end
166
+
167
+ def integer_value(value)
168
+ return 0 if value.nil? || value.to_s.empty?
169
+
170
+ value.to_i
171
+ end
172
+
173
+ def validate_capture_target!(options)
174
+ return if present?(options[:html])
175
+ return if present?(options[:url])
176
+
177
+ raise ArgumentError, "URL or HTML is required"
178
+ end
179
+
180
+ def normalize_base_url(base_url)
181
+ value = base_url.to_s.strip
182
+ raise ArgumentError, "base_url is required" if value.empty?
183
+
184
+ value.sub(%r{/+\z}, "")
185
+ end
186
+
187
+ def blank?(value)
188
+ !present?(value)
189
+ end
190
+
191
+ def present?(value)
192
+ !value.nil? && !value.to_s.strip.empty?
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,44 @@
1
+ module ScreenshotAPI
2
+ class APIError < StandardError
3
+ attr_reader :status, :code
4
+
5
+ def initialize(message, status:, code:)
6
+ super(message)
7
+ @status = status
8
+ @code = code
9
+ end
10
+ end
11
+
12
+ class AuthenticationError < APIError
13
+ def initialize(message)
14
+ super(message, status: 401, code: "authentication_error")
15
+ end
16
+ end
17
+
18
+ class InsufficientCreditsError < APIError
19
+ attr_reader :balance
20
+
21
+ def initialize(message, balance: 0)
22
+ super(message, status: 402, code: "insufficient_credits")
23
+ @balance = balance
24
+ end
25
+ end
26
+
27
+ class InvalidAPIKeyError < APIError
28
+ def initialize(message)
29
+ super(message, status: 403, code: "invalid_api_key")
30
+ end
31
+ end
32
+
33
+ class ScreenshotFailedError < APIError
34
+ def initialize(message)
35
+ super(message, status: 500, code: "screenshot_failed")
36
+ end
37
+ end
38
+
39
+ class NetworkError < APIError
40
+ def initialize(message)
41
+ super(message, status: nil, code: "network_error")
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ module ScreenshotAPI
2
+ class Metadata
3
+ attr_reader :credits_remaining, :screenshot_id, :duration_ms
4
+
5
+ def initialize(credits_remaining:, screenshot_id:, duration_ms:)
6
+ @credits_remaining = credits_remaining
7
+ @screenshot_id = screenshot_id
8
+ @duration_ms = duration_ms
9
+ end
10
+ end
11
+
12
+ class Result
13
+ attr_reader :image, :content_type, :metadata
14
+
15
+ def initialize(image:, content_type:, metadata:)
16
+ @image = image
17
+ @content_type = content_type
18
+ @metadata = metadata
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,3 @@
1
+ module ScreenshotAPI
2
+ VERSION = "1.0.0"
3
+ end
@@ -0,0 +1,9 @@
1
+ require_relative "screenshotapi/version"
2
+ require_relative "screenshotapi/client"
3
+ require_relative "screenshotapi/errors"
4
+ require_relative "screenshotapi/result"
5
+
6
+ module ScreenshotAPI
7
+ DEFAULT_BASE_URL = "https://screenshotapi.to"
8
+ DEFAULT_TIMEOUT = 60
9
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: screenshotapi_to
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - ScreenshotAPI
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-06-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: minitest
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '5.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '5.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ description: Capture website screenshots with the ScreenshotAPI service. Simple, fast,
42
+ and reliable.
43
+ email:
44
+ - support@screenshotapi.to
45
+ executables: []
46
+ extensions: []
47
+ extra_rdoc_files: []
48
+ files:
49
+ - CHANGELOG.md
50
+ - LICENSE
51
+ - README.md
52
+ - examples/plain_ruby.rb
53
+ - examples/rails_controller.rb
54
+ - lib/screenshotapi.rb
55
+ - lib/screenshotapi/client.rb
56
+ - lib/screenshotapi/errors.rb
57
+ - lib/screenshotapi/result.rb
58
+ - lib/screenshotapi/version.rb
59
+ homepage: https://screenshotapi.to
60
+ licenses:
61
+ - MIT
62
+ metadata:
63
+ allowed_push_host: https://rubygems.org
64
+ bug_tracker_uri: https://github.com/miketromba/screenshotapi-ruby/issues
65
+ changelog_uri: https://github.com/miketromba/screenshotapi-ruby/blob/main/CHANGELOG.md
66
+ documentation_uri: https://screenshotapi.to/docs/sdks/ruby
67
+ homepage_uri: https://screenshotapi.to
68
+ rubygems_mfa_required: 'true'
69
+ source_code_uri: https://github.com/miketromba/screenshotapi-ruby
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: 3.0.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements: []
85
+ rubygems_version: 3.5.22
86
+ signing_key:
87
+ specification_version: 4
88
+ summary: Official Ruby SDK for ScreenshotAPI
89
+ test_files: []