# Hidden and Flexible Inputs - Advanced Input Handling Source: ## Hidden inputs Alongside the `required` and `optional` inputs, which create corresponding inputs or widgets on the client-side, there are three `hidden` input options which allow the custom node to request certain information from the server. These are accessed by returning a value for `hidden` in the `INPUT_TYPES` `dict`, with the signature `dict[str,str]`, containing one or more of `PROMPT`, `EXTRA_PNGINFO`, or `UNIQUE_ID` ```python @classmethod def INPUT_TYPES(s): return { "required": {...}, "optional": {...}, "hidden": { "unique_id": "UNIQUE_ID", "prompt": "PROMPT", "extra_pnginfo": "EXTRA_PNGINFO", } } ``` ### UNIQUE_ID `UNIQUE_ID` is the unique identifier of the node, and matches the `id` property of the node on the client side. It is commonly used in client-server communications (see messages). ### PROMPT `PROMPT` is the complete prompt sent by the client to the server. See the prompt object for a full description. ### EXTRA_PNGINFO `EXTRA_PNGINFO` is a dictionary that will be copied into the metadata of any `.png` files saved. Custom nodes can store additional information in this dictionary for saving (or as a way to communicate with a downstream node). > **Tip**: Note that if Comfy is started with the `disable_metadata` option, this data won't be saved. ### DYNPROMPT `DYNPROMPT` is an instance of `comfy_execution.graph.DynamicPrompt`. It differs from `PROMPT` in that it may mutate during the course of execution in response to Node Expansion. > **Tip**: `DYNPROMPT` should only be used for advanced cases (like implementing loops in custom nodes). ## Flexible inputs ### Custom datatypes If you want to pass data between your own custom nodes, you may find it helpful to define a custom datatype. This is (almost) as simple as just choosing a name for the datatype, which should be a unique string in upper case, such as `CHEESE`. You can then use `CHEESE` in your node `INPUT_TYPES` and `RETURN_TYPES`, and the Comfy client will only allow `CHEESE` outputs to connect to a `CHEESE` input. `CHEESE` can be any python object. The only point to note is that because the Comfy client doesn't know about `CHEESE` you need (unless you define a custom widget for `CHEESE`, which is a topic for another day), to force it to be an input rather than a widget. This can be done with the `forceInput` option in the input options dictionary: ```python @classmethod def INPUT_TYPES(s): return { "required": { "my_cheese": ("CHEESE", {"forceInput":True}) } } ``` ### Wildcard inputs ```python @classmethod def INPUT_TYPES(s): return { "required": { "anything": ("*",{})}, } @classmethod def VALIDATE_INPUTS(s, input_types): return True ``` The frontend allows `*` to indicate that an input can be connected to any source. Because this is not officially supported by the backend, you can skip the backend validation of types by accepting a parameter named `input_types` in your `VALIDATE_INPUTS` function. (See VALIDATE_INPUTS for more information.) It's up to the node to make sense of the data that is passed. ### Dynamically created inputs If inputs are dynamically created on the client side, they can't be defined in the Python source code. In order to access this data we need an `optional` dictionary that allows Comfy to pass data with arbitrary names. Since the Comfy server ```python class ContainsAnyDict(dict): def __contains__(self, key): return True ... @classmethod def INPUT_TYPES(s): return { "required": {}, "optional": ContainsAnyDict() } ... def main_method(self, **kwargs): # the dynamically created input data will be in the dictionary kwargs ``` > **Tip**: Hat tip to rgthree for this pythonic trick!