Proxhook - A Module for proxying discord webhooks!

e68e3783e487bc123af4bdff46c6fbc3

  • A module which proxies discord webhooks using Hyra (a Free & Open-Source proxy for discord).
    (All credit for Hyra goes to @melodrvma)

Features

Managed Requests

Using the rate-limit information Hyra provides, Requests that are being rate-limited are stored until the rate-limit window has reset. in other words : if your request is valid, it won’t get dropped.

Simple Usage

A Discord webhook should be structured similar to this : https://discord.com/api/webhooks/ID/TOKEN
and using Proxhook is just a matter of plugging in the ID, TOKEN, & the data you want to send.

local Proxhook = require(script.Proxhook);

local Success = Proxhook(ID, TOKEN, DATA); -- <@Success> : boolean

And for those who aren’t familiar with the discord webhook api,
you can find more information on the Discord Developer Portal

And I’ll be adding more soon.

Why do requests need to be proxied?

As many people may know by now, Discord has blocked HTTP Requests coming Roblox servers.
which is an issue for developers who use discord webhooks to connect Roblox experiences to discord, may this be through creating moderation logs, error logs, or player reports.

And after looking for solutions, I had found Hyra to be one of the easist to use.

Along with re-enabling the use of webhooks, it also provides rate-limit information in response headers
which allows for further management of http requests.

Source

Module : https://www.roblox.com/library/7719426842/Proxhook

Code :
--[[


β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–‘β–ˆβ–ˆβ•—β–‘β–‘β–ˆβ–ˆβ•—β–ˆβ–ˆβ•—β–‘β–‘β–ˆβ–ˆβ•—β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–‘β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•—β–‘β–ˆβ–ˆβ•—β–‘β–‘β–ˆβ–ˆβ•—
β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–‘β–ˆβ–ˆβ•”β•
β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–‘β•šβ–ˆβ–ˆβ–ˆβ•”β•β–‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•β•β–‘
β–ˆβ–ˆβ•”β•β•β•β•β–‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–‘β–ˆβ–ˆβ•”β–ˆβ–ˆβ•—β–‘β–ˆβ–ˆβ•”β•β•β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•—β–‘
β–ˆβ–ˆβ•‘β–‘β–‘β–‘β–‘β–‘β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ•—β–ˆβ–ˆβ•‘β–‘β–‘β–ˆβ–ˆβ•‘β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β•šβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ•”β•β–ˆβ–ˆβ•‘β–‘β•šβ–ˆβ–ˆβ•—
β•šβ•β•β–‘β–‘β–‘β–‘β–‘β•šβ•β•β–‘β–‘β•šβ•β•β–‘β•šβ•β•β•β•β•β–‘β•šβ•β•β–‘β–‘β•šβ•β•β•šβ•β•β–‘β–‘β•šβ•β•β–‘β•šβ•β•β•β•β•β–‘β–‘β•šβ•β•β•β•β•β–‘β•šβ•β•β–‘β–‘β•šβ•β•


Discription : A Proxy module for using webhooks, Default proxy is 'Hyra.io'.

Credits :
	
	StyledDev (roblox.com/users/2391664934/profile) - [For this module]
	samueIox (roblox.com/users/121647898/profile) - [For Hyra.io]

Check out Proxhook on the devforum :
	https://devforum.roblox.com/t/proxhook-a-module-for-proxying-discord-webhooks/1505544

Or on Github :
	https://github.com/Shambi-0/Proxhook

Aswell as Hyra : 
	https://devforum.roblox.com/t/discord-webhook-proxy/1500688

--]]

--------------------------
--// Type Definitions //--
--------------------------

type Dictionary<Type> = {[string] : Type};
type Array<Type> = {[number] : Type};

type Dataset = (string | {[any] : any})?

------------------
--// Services //--
------------------

-- Service used for sending & receiving http requests over the internet.
local HttpService : HttpService = game:GetService("HttpService");

-------------------
--// Variables //--
-------------------

-- Hyra Proxy Url, Which will be further modified.
local Url : string = "https://hooks.hyra.io/api/webhooks/%s/%s";

--[[
Stores the information required
to work with the rate limit.
--]]
local RateLimit : Dictionary<number> = {

	Reset = 0, --> When this rate limiting window will reset.
	Limit = 0xf, --> How many requests in this window you have remaining.
	Retry = 0  --> The amount of seconds you have left on the rate limit.
};

--[[
Requests caught up in the Rate limit will be
stored in 'Cache' until the rate limit is over.
--]]
local Cache : Array<Array<string>> = {};

-------------------
--// Functions //--
-------------------

-- Sends the remaining requests stored in 'Cache'.
function UpdateCache()

	-- The remaining requests that did not make it, will be put back into the 'Cache'.
	local Left : Array<Array<string>> = {};

	-- Cycle through the remaining requests.
	for _, Data : Array<string> in ipairs(Cache) do

		-- Check if we are operating under the rate limit.
		if (0 < RateLimit.Limit) then

			-- Unpack the request and post it to the cached 'Destination'.
			local Response = HttpService:PostAsync(unpack(Data)); --> Example Request : '{Destination : string, Data : string}'

			if (Response ~= "") then

				-- Create a direct reference to the headers given in the response.
				local Headers : Dictionary<any> = Response.Headers;

				-- Update rate limit stats based off headers.
				RateLimit.Reset = Headers["x-ratelimit-reset"];
				RateLimit.Limit = Headers["x-ratelimit-remaining"];

				-- check if a response body was provided.
				if (Response.Body ~= "") then

					-- if so, decode body from json to a table.
					local Decoded : Dictionary<any> = HttpService:JSONDecode(Response.Body);

					-- Update rate limit stat based off the response body.
					RateLimit.Retry = if (typeof(Decoded.retry_after) == "number") then Decoded.retry_after else 0;
				end;
			end;
		else
			--[[
			If we are over the rate limit, then
			Add the Request back to 'Cache' to
			be sent the next update session.
			--]]
			table.insert(Left, Data);
		end;
	end;

	-- Update 'Cache' to contain the remaining requests.
	Cache = Left;
	return;
end;

----------------------
--[[ Finalization ]]--
----------------------

return (function(Id : string | number, Token : string, Data : Dataset) : boolean

	-- Catch possible issues, and log messages accordingly.
	assert(typeof(Token) == "string", "Proxhook : \"Token\" is expected to be a \"string\".");
	assert(not (typeof(Id) ~= "string" and typeof(Id) ~= "number"), "Proxhook : \"Id\" is expected to be either a \"string\" or a \"number\".");

	-- Format url so it may be used to proxy requests.
	local FormattedUrl : string = string.format(Url, Id, Token);

	--[[
	Pass through a pcall to catch error that
	may occur when sending an http request.
	--]]
	local Success : boolean, Error : string | nil = pcall(function()

		-- Convert Data into a string if it's not already.
		local Processed : string = type(Data) == "string" and Data or HttpService:JSONEncode(Data);

		-- Add Request to cache to be managed further.
		table.insert(Cache, {FormattedUrl, Processed});

		-- Update Cache to send remaining & new requests.
		UpdateCache();
	end);

	if (Error) then
		warn(string.format("Proxhook : %s", Error))
	end;

	--[[
	Return a boolean value
	to indecate the success
	and to make this function valid.
	--]]
	return (Success);
end);

And Hyra’s source code can be found here.

Notes :

  • This module is in it’s early stages, I plan to build upon this module a bit more when I have the time
    & I’ll be updating this post as I do so.

  • I’m always open to suggestions! so if you think this needs something, or you found a bug.
    feel free to let me know here. :sweat_smile:

  • For those who are concerned about this breaking discord’s TOS, Here is a tweet by one of Discord’s back-end developers : https://twitter.com/lolpython/status/967211620970545153

21 Likes

This is perfect! I tried this myself, and it works just like it would with normal webhooks.

Do you mean discord will stop accepting HTTP requests from roblox servers in the future? If this is true can you provide a link to discord stating this? Because I can send requests to my server’s webhooks just fine.

I’m not sure why you’re ok, but there is a bug report on it. Discord webhooks don’t work ingame

1 Like

Thank you, it was working because I was sending requests within roblox studio.

ummmm i may be dumb but whats the webhook id and token and where do i get that

So, let’s say your discord webhook was :
https://discord.com/api/webhooks/9210839739840/AJshjHAJKHjhdhkd

Your ID would be 9210839739840
And your Token AJshjHAJKHjhdhkd

1 Like

Never share your WebhookID and your Token! It is confidential!

Discord has blocked Hyra unfortunately. Hopefully a new software is made soon.

Do you mean the Hyra’s server? or the actual software?

If it’s just the server, then hosting Hyra’s source code should still work.

I probably should have been more specific, my bad. I meant β€œhooks.hyra.io” is blocked.

Are you sure it is blocked?
I just tested it and it appears to still be working?

1 Like

Please, please PLEASE don’t use Discord for logging information! There’s a chance your Discord account can get suspended due to this, as Discord is not a platform meant for logging information. A couple years ago, some Roblox developers received emails from Discord for sending too many logs onto their server. This is the main reason Roblox was removed from being able to send Discord webhooks as well. If you want to log information, use something else. Other than that, you’re fine using Discord webhooks as long as you’re not trying to log pieces of information.

1 Like

You are allowed to use Discord for logging, and it’s one of the main uses of webhooks.
As you mentioned, ROBLOX Developers were suspended for sending too many logs. which means they
were probably going over the rate-limit, which if you read the "Why do requests need to be proxied?" section of the original post, this module is designed to comply with.

so as long as the content you send via webhooks abides by Discord’s Terms-of-Service, logging information should be completely safe.

This was also answered here.

You can also use google sprite sheets for logging. I do it all the time. Works great. No rate limits, nada.

1 Like

It was blocked before, now it is not.

You can, but some people find discord convenient, especially for community or staff servers.

Ah, alright. good to know :+1:

Github & Updates!


To make it easier to release updates, Proxhook now
includes a Github repository which can be found here!


In addition, I have made a couple changes to the module itself :

  • Updated much of the Type-Annotation.
  • Removed much of the β€œextra” in most of the comments.
  • Made several optimizations to make use of some of Luau’s updates.
  • Incorrectly using some arguments will now log a more descriptive error message.

Sadly I haven’t gotten as much time as I had hoped to work on this.
but be aware that I do still intend on improving on this module in the future!


As always : if you have suggestions, questions,
issues, concerns, or would like to become a contributor.

Feel free to contact me :

1 Like