The Wirecard Fiasco: Digital Payments Gone Wrong

What would you do if your credit card processor and merchant account provider were fraudulent? That’s the reality for many thousands of worldwide businesses that relied on Wirecard, the Germany-based financial technology firm that is now in bankruptcy proceedings, having committed, allegedly, sham practices for years.

I’ll describe the Wirecard fiasco in this post. It’s shocking because of the apparent widespread level of fraud and the lessons for the digital payments industry.

Image of Wirecard headquarters near Munich, Germany. Source: Wikipedia.

Wirecard headquarters near Munich, Germany. Source: Wikipedia.

A Sketchy Start?

Wirecard is a multinational payment processor, merchant acquirer, card issuer, and technology service provider. The company declared bankruptcy in August 2020. It was listed on the German DAX, a notable stock index similar to the Dow Jones Industrial Average.

Wirecard launched in 1999 as a payment-technology company. In 2002, Wirecard’s then CEO, Marcus Braun (who is now under arrest), shifted strategy to processing payments for, mainly, gambling and pornography websites.

In 2005, Wirecard raised funds by issuing shares in the Frankfurt Stock Exchange through a reverse IPO, having purchased the listing of a failed call center company named InfoGenie. This allowed Wirecard to expedite going public and, some would say, avoid much of the scrutiny.

With the new capital, Wirecard acquired a German bank called XCOM, which held international merchant acquiring and card issuing licenses, thereby allowing the newly created Wirecard Bank to become both a worldwide issuer and acquirer. Purchasing companies for their licenses is fairly common.

The XCOM transaction transformed Wirecard into a sprawling, complex business. In the ensuing 14 years, Wirecard allegedly used this complexity to artificially inflate profits, hide massive losses, forge contracts, and dupe investors, auditors, and regulators.

Rise and Fall

From 2006 to 2018, Wirecard expanded aggressively. It acquired several smaller, Asia-based payment processors, an Indian payments company, and several Citibank-owned processing and prepaid-card portfolios in Asia and North America.

Business for Wirecard was, reportedly, booming. At its peak in 2018, Wirecard’s public valuation was €24 billion (roughly USD $28 billion at the time of writing). The company had 5,000 employees and claimed to process payments for 250,000 merchants worldwide in addition to its card-issuing and technology operations. Wirecard replaced one of Germany’s largest banks on the DAX-30 index.

So, what went wrong?

A lot. It’s useful to examine the scandal’s timeline to understand the level of fraud, collusion, and deceit. The Financial Times, which exposed the apparent depth of the scandal, offers excellent coverage.

  • 2015 and 2016. The Financial Times and short-sellers begin to probe. BaFin — Federal Financial Supervisory Authority, Germany’s principal financial regulator — sides with Wirecard. As far back as 2008, a small group of Wirecard shareholders complained about what they believed were accounting irregularities. Wirecard hired Ernst & Young, the accounting firm, to investigate. The complainants were silenced, two investors were prosecuted for insider trading, and Wirecard escaped unscathed. Ernst & Young would become Wirecard’s outside auditor for the next 11 years.
  • 2008 through 2015. Wirecard expanded rapidly and, for the most part, avoided controversy. In 2015, however, a Financial Times report alleged significant accounting problems in, primarily, Wirecard’s payment-processing business. Later in 2015, a group of short-sellers claimed that Wirecard’s operations in Asia were much smaller than reported by the company.

Nonetheless, Wirecard acquired a payment processor in India for, reportedly, €340 million (USD $401 million). The Financial Times later alleged that Indian shareholders never received €175 million to €285 million from the sale.

  • 2016. A group of short-sellers published allegations against Wirecard, including money laundering. BaFin, the German regulator, investigated but ultimately sided with Wirecard. This became a recurring pattern: Whistleblowers and journalists accuse Wirecard of improprieties, and regulators side with the company.

Unscathed, Wirecard acquired Citigroup’s North America prepaid-card business, giving Wirecard a foothold in the U.S.

  • 2018 to 2019. In early 2018, a whistleblower in Wirecard’s Singapore office alleged that the company was defrauding investors by engaging in “round-tripping,” a practice of selling something and then refunding the buyer later — the sold assets are never transferred from the seller to the buyer. The transaction is fake (and illegal).

Concerned employees in Singapore took this accusation seriously and initiated an internal investigation. In October 2018, the employees contacted The Financial Times, which published a report on Wirecard’s Singapore operations. Another BaFin investigation occurred. Singaporean law enforcement became involved, leading to a raid of Wirecard’s offices.

BaFin regulators, again, sided with Wirecard. BaFin announced a two-month prohibition on short-selling Wirecard’s stock, claiming that Wirecard is too important to the health of the German economy.

  • 2019. Fake companies and fake profits. In March of 2019, The Financial Times published a report claiming that roughly half of Wirecard’s revenue and most of its profit are from referral fees with smaller processor partners. This isn’t unusual as most large processors work closely with merchant account providers and other partners.

But many of Wirecard’s processing partners did not exist. They were fake. Indeed, when they attempted to visit the offices of Wirecard’s partners in the Philippines, reporters discovered dwellings of uninvolved residents.

Wirecard’s response was to sue The Financial Times and the Singapore authorities, who earlier had named five Wirecard employees and eight partner companies as suspects in a criminal investigation.

Ernst & Young, the auditors, approved Wirecard’s 2018 financial statements and recommended only minor compliance procedures for Wirecard’s Singapore office.

  • October 2019. The Financial Times reported that profits from Wirecard’s operations in Dubai and Ireland were also inflated and that even more of the company’s partners did not exist. Pressure mounting, Wirecard appointed KPMG, another accounting firm and a competitor to Ernst & Young, to conduct an audit.
  • 2020. Wirecard’s demise. After a series of delays, KPMG published its reports. The findings shocked investors, BaFin, and the German police.

KPMG challenged the authenticity of Wirecard’s profits from 2016 to 2018, citing a glaring lack of evidence, such as no bank statements showing income received. KPMG could not confirm at least 34 Wirecard clients and at least €1 billion in cash. Wirecard had fabricated at least three years of profits.

In early June, German authorities raided Wirecard’s headquarters and launched a criminal investigation against Wirecard’s CEO and several other executives.

On June 16, two Philippine banks disclosed that documents provided by Wirecard to authorities to support €1.9 billion in cash balances were “spurious” (fake). Two days later, Wirecard announced that the €1.9 billion is “missing.” Wirecard’s stock price crashed, and its creditors called in approximately €2 billion in loans.

Following its CEO’s resignation, Wirecard’s new management acknowledged the colossal scale of a multi-year accounting fraud, adding a “prevailing likelihood” that €1.9 billion that was supposed to be in its accounts does not exist.

On June 25, following the arrest of its former CEO, Wirecard announced that it would file for insolvency (bankruptcy).

Build And Deploy An Angular Form With Netlify Forms And Edge

Creating the frontend, backend, and deployment workflow of an app takes a lot of work. In instances where your app collects only a limited amount of data submissions from its users, building a whole backend may not seem worth the time and effort. An alternative to developing a complete backend is using Netlify Forms. In this tutorial, I’ll explain how you could use an Angular reactive form with Netlify Forms. Since Netlify Forms only work when deployed on Netlify, I’ll also illustrate how to deploy your app on Netlify Edge.

The Toolkit

An Angular reactive form is a form that has a structured data model created explicitly within a component class using the ReactiveFormsModule providers. A form model is created for each input element within the form view. This form model is an instance of the FormControl class and it keeps track of the value of the form element. The form model is immutable because whenever a change is made to the model the FormControl instance returns a new data model instead of updating the old model. Its immutability makes change detection more efficient and allows data alteration with observable operators. Since form input elements are directly connected to their form models, updates between them are synchronous and do not rely on UI rendering.

Netlify is a platform that allows you to build, deploy, and host sites built with various technologies. Sites built with Angular can be hosted on Netlify. Netlify additionally provides a host of tools that simplify, automate, and augment builds and deployments of these sites. We’re going to use two of its products in this tutorial: Netlify Edge and Netlify Forms.

As described earlier, Netlify Forms is a form handling feature that receives submissions from HTML forms automatically. It does not require any submission processing configuration, like creating APIs, scripts, etc. This feature only works with forms in sites deployed on Netlify. It is enabled by default, further reducing the configuration needed to set up the form submissions. Submission handling is set up during deployment where a site’s HTML files are parsed by Netlify’s build bots.

Netlify Edge is a global application delivery network on which sites and applications are published. It provides features like A/B testing, rollbacks, staging, and phased rollouts. All deployments on Netlify Edge are atomic, meaning a site is only live when all files have been uploaded/updated and changes to the site are ready. Once a site is deployed, it is assigned a subdomain on netlify.app when deployed to production. Netlify Edge also supports preview and branch deployments (staging, development, etc.).

Netlify Forms submission-handling works because build bots parse HTML forms on a site during deployment. Client-side Javascript rendered forms like those in compiled Angular sites won’t be found by these bots. So the normal set up for Netlify Forms won’t work with Angular Forms.

However, there is a work-around to this. To get it to receive submissions, a hidden plain HTML form is added to the index.html file. This form works with the build bots. When submitting the Angular Form, a post request is made to this hidden form which is then captured by Netlify Forms.

In this article, we will create a reactive form. We’ll also develop a service to make a post request to the hidden HTML form. Lastly, we will deploy the app to Netlify Edge.

Example

To illustrate how to build the app, we will take an example of a feedback form common on many websites. We will use this form to collect comments/complaints, questions, and suggestions from users of the site along with their name and email. We shall also use it to collect their rating of the site.

Requirements

To follow along with this tutorial, you will need a Netlify account and the Angular CLI installed. If you do not have the CLI, you can install it using npm.

npm install -g @angular/cli

If you’ve not signed up for a Netlify account yet, you can create one here. Netlify offers sign-up through Github, Gitlab, Bitbucket, or Email. Depending on what deployment method you choose to go with, they may be other requirements. They will be stated under each deployment method.

Setting Up The App

To start, we will create the app and call it feedback. When creating it, add routing to it when asked in the prompts.

ng new feedback

Next, we’ll generate three components: a feedback form, a successful submission message page, and a 404 page. Netlify Forms allow you to navigate to a page upon successful form entry submission. That’s what we’ll use the SuccessComponent for.

ng g c feedback
ng g c success
ng g c page-not-found

After generating the components, we’ll add the routes to each page in the AppRoutingModule within the app-routing.module.ts file.

const routes: Routes = [ { path:'', component: FeedbackComponent }, { path: 'success', component: SuccessComponent }, { path: '**', component: PageNotFoundComponent }
];

We’ll use the FormBuilder service to create our reactive form. This is because it is more convenient and less repetitive than using basic form controls. To have access to it, we’ll need to register the ReactiveFormsModule in the app.module.ts file.

Since we will be making a post request to the hidden HTML form, we also have to register the HttpClientModule.

import { ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http'; @NgModule({ imports: [ // other imports ReactiveFormsModule, HttpClientModule ]
})
export class AppModule { }

Proceed to change the contents of app.component.html to just have the router outlet.

<router-outlet></router-outlet>

The different pages will share some styling. So add the styling below to styles.css.

html, body { height: 100%; width: 100%; display: flex; align-items: flex-start; justify-content: center;
} h1 { margin: 0; text-align: center;
} h1, p, label { font-family: Arial, Helvetica, sans-serif;
} p { max-width: 25rem;
} #container { border: none; padding: .4rem; border-radius: 0; flex-direction: column; display: flex;
} hr { width: 80%;
} button { color: white; background-color: black; font-size: large; padding: .5rem; border-radius: .5rem; margin-top: 1rem;
} @media screen and (min-height: 700px) { html, body { align-items: center; justify-content: center; }
} @media screen and (min-width: 480px) { #container { border: .1rem solid lightgray; padding: 2rem; border-radius: .5rem; } html, body { align-items: center; justify-content: center; }
}

Create The Reactive Form

In our FeedbackComponent class, we will begin by importing the FormBuilder service which we’ll use to create the form. We’ll also import the Validators class for form input validation.

import { FormBuilder, Validators } from '@angular/forms';

We will then inject the FormBuilder service by adding it to the FeedbackComponent constructor.

constructor(private fb: FormBuilder) { }

Next, we’ll define the form model using the group method of the injected FormBuilder service. We’ll also add an errorMsg property to hold any errors we may encounter when submitting the form input. Also included is a closeError method that will close the error alert that displays on the form.

Each control in the form model will be verified using validators from the Validators class. If any of the inputs fail validation, the form will be invalid and submission will be disabled. You can choose to add multiple validators to a form control like in the case of the email control.

export class FeedbackComponent { feedbackForm = this.fb.group({ firstName: ['', Validators.required], lastName: ['', Validators.required], email: ['', [Validators.email, Validators.required]], type: ['', Validators.required], description: ['', Validators.required], rating: [0, Validators.min(1)] }); errorMsg = ''; closeError() { this.errorMsg = ''; } // ...
}

In the component’s template (feedback.component.html), we shall add this.

<div id="container"> <div class="error" [class.hidden]="errorMsg.length == 0"> <p>{{errorMsg}}</p> <span (click)="closeError()" class="close">✖︎</span> </div> <h1>Feedback Form</h1> <hr> <p>We’d like your feedback to improve our website.</p> <form [formGroup]="feedbackForm" name="feedbackForm" (ngSubmit)="onSubmit()"> <div id="options"> <p class="radioOption"> <input formControlName="type" type="radio" id="suggestion" name="type" value="suggestion"> <label for="suggestion">Suggestion</label><br> </p> <p class="radioOption"> <input formControlName="type" type="radio" id="comment" name="type" value="comment"> <label for="comment">Comment</label><br> </p> <p class="radioOption"> <input formControlName="type" type="radio" id="question" name="type" value="question"> <label for="question">Question</label><br> </p> </div> <div class="inputContainer"> <label>Description:</label> <textarea rows="6" formControlName="description"></textarea> </div> <div class="inputContainer"> <div id="ratingLabel"> <label>How would you rate our site?</label> <label id="ratingValue">{{feedbackForm.value?.rating}}</label> </div> <input formControlName="rating" type="range" name="rating" max="5"> </div> <div class="inputContainer"> <label>Name:</label> <div class="nameInput"> <input formControlName="firstName" type="text" name="firstName" placeholder="First"> <input formControlName="lastName" type="text" name="lastName" placeholder="Last"> </div> </div> <div class="inputContainer"> <label>Email:</label> <input formControlName="email" type="email" name="email"> </div> <div class="inputContainer"> <button type="submit" [disabled]="feedbackForm.invalid">Submit Feedback</button> </div> </form>
</div>

Note that the form element should have the [formGroup]="feedbackForm" attribute corresponding to the model we just created. Also, each of the input elements should have a formControlName="" attribute corresponding to its counterpart form control in the model.

To style the form, add this tofeedback.component.css.

#options { display: flex; flex-direction: column;
} #options label { margin: 0 0 0 .2rem;
} .radioOption { margin: 0 0 .2rem 0;
} .inputContainer { display: flex; flex-direction: column; margin: .5rem 0 .5rem 0;
} label { margin: .5rem 0 .5rem 0;
} .nameInput { display: flex; flex-direction: column;
} button:disabled { cursor: not-allowed; pointer-events: all; background-color: slategrey;
} #ratingLabel { display: flex; justify-content: space-between; margin: .5rem 0 .5rem 0;
} #ratingValue { font-weight: bolder; font-size: large; border: .1rem solid lightgray; padding: .4rem .6rem .1rem .6rem; margin: 0; vertical-align: middle; border-radius: .3rem;
} .error { color: darkred; background-color: lightsalmon; border: .1rem solid crimson; border-radius: .3rem; padding: .5rem; text-align: center; margin: 0 0 1rem 0; display: flex; width: inherit;
} .error p { margin: 0; flex-grow: 1;
} textarea, input { margin: .1rem; font-family: Arial, Helvetica, sans-serif; padding: 5px; font-size: medium; font-weight: lighter;
} .close { cursor: default;
} .hidden { display: none;
} @media screen and (min-width: 480px) { #options { flex-direction: row; justify-content: space-around; } .nameInput { flex-direction: row; justify-content: space-between; }
}

This is what the form will look like:

Adding A Hidden HTML Form

As stated earlier, we need to add a hidden HTML form that the Netlify Forms build bots can parse. Submissions will then be sent from our reactive form to the hidden HTML form. The HTML form is put in the index.html file.

This form should have the same name as the reactive form. Additionally, it should contain three other attributes: netlify, netlify-honeypot, and hidden. The bots look for any forms that have the netlify attribute so that Netlify can process inputs from them. The netlify-honeypot attribute is added to prevent captchas from being shown when a submission is made and enables extra spam protection.

<!doctype html>
<html lang="en">
<!-- Head --> <body> <form name="feedbackForm" netlify netlify-honeypot="bot-field" hidden> <input type="text" name="firstName"/> <input type="text" name="lastName"/> <input type="text" name="email"/> <input type="text" name="feedbackType"/> <input type="text" name="description"/> <input type="text" name="rating"/> </form> <app-root></app-root> </body>
</html>

It’s important to note that since you can’t set the value of file input elements, you can’t upload a file using this method.

Making A Post Request To The Hidden Form

To send a submission from the reactive form to the HTML form, we’ll make a post request containing the submission to index.html. The operation will be performed in the onSubmit method of the FeedbackComponent.

However, before we can do that, we need to create two things: a Feedback interface and a NetlifyFormsService. Let’s start with the interface.

touch src/app/feedback/feedback.ts

The contents of this file will be:

export interface Feedback { firstName: string; lastName: string; email: string; type: string; description: string; rating: number;
}

The NetlifyFormsService will contain a public method to submit a feedback entry, a private method to submit a generic entry, and another private one to handle any errors. You could add other public methods for additional forms.

To generate it, run the following:

ng g s netlify-forms/nelify-forms

The submitEntry method returns an Observable<string> because Netlify sends a HTML page with a success alert once we post data to the form. This is the service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse, HttpParams } from '@angular/common/http';
import { Feedback } from '../feedback/feedback';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators'; @Injectable({ providedIn: 'root'
})
export class NetlifyFormsService { constructor(private http: HttpClient) { } submitFeedback(fbEntry: Feedback): Observable { const entry = new HttpParams({ fromObject: { 'form-name': 'feedbackForm', ...fbEntry, 'rating': fbEntry.rating.toString(), }}); return this.submitEntry(entry); } private submitEntry(entry: HttpParams): Observable { return this.http.post( '/', entry.toString(), { headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, responseType: 'text' } ).pipe(catchError(this.handleError)); } private handleError(err: HttpErrorResponse) { let errMsg = ''; if (err.error instanceof ErrorEvent) { errMsg = A client-side error occurred: ${err.error.message}; } else { errMsg = A server-side error occurred. Code: ${err.status}. Message: ${err.message}; } return throwError(errMsg); }
}

We’ll send the form submission as HttpParams. A header for the ContentType should be included with the value application/x-www-form-urlencoded. The responseType option is specified as text because if successful, posting to the hidden form will return an HTML page containing a generic success message from Netlify. If you do not include this option, you will get an error because the response will be parsed as JSON. Below is a screenshot of the generic Netlify success message.

In the FeedbackComponent class, we shall import the NetlifyFormsService and Router. We’ll submit the form entry using the NetlifyFormsService.submitEntry method. If the submission is successful, we will redirect to the successful submission page and reset the form. We’ll use the Router service for the redirection. If unsuccessful, the errorMsg property will be assigned the error message and be displayed on the form.

import { Router } from '@angular/router';
import { NetlifyFormsService } from '../netlify-forms/netlify-forms.service';

After that, inject both the NetlifyFormsService and Router in the constructor.

constructor( private fb: FormBuilder, private router: Router, private netlifyForms: NetlifyFormsService
) {}

Lastly, call the NetlifyFormsService.submitEntry method in FeedbackComponent.onSubmit.

onSubmit() {
this.netlifyForms.submitFeedbackEntry(this.feedbackForm.value).subscribe( () => { this.feedbackForm.reset(); this.router.navigateByUrl('/success'); }, err => { this.errorMsg = err; } );
}

Create A Successful Submission Page

When a user completes a submission, Netlify returns a generic success message shown in the last screenshot of the previous section. However, you can link back to your own custom success message page. You do this by adding the action attribute to the hidden HTML form. Its value is the relative path to your custom success page. This path must start with / and be relative to your root site.

Setting a custom success page, however, does not seem to work when using a hidden HTML form. If the post request to the hidden HTML form is successful, it returns the generic Netlify success message as an HTML page. It does not redirect even when an action attribute is specified. So instead we shall navigate to the success message page after a submission using the Router service.

First, let’s add content to the SuccessComponent we generated earlier. In success.component.html, add:

<div id="container"> <h1>Thank you!</h1> <hr> <p>Your feedback submission was successful.</p> <p>Thank you for sharing your thoughts with us!</p> <button routerLink="/">Give More Feedback</button>
</div>

To style the page, add this to success.component.css:

p { margin: .2rem 0 0 0; text-align: center;
}

This is what the page looks like:

In the FeedbackComponent class, we already added the Routerservice as an import and injected it into the constructor. In its onSubmitmethod, after the request is successful and the form has reset, we navigate to the successful submission page, /success. We use the navigateByUrl method of the router to do that.

Creating The 404 Page

The 404 page may not be necessary but is a nice to have. The contents of page-not-found.component.html would be:

<div id="container"> <h1>Page Not Found!</h1> <hr> <p>Sorry! The page does not exist.</p> <button routerLink="/">Go to Home</button>
</div>

To style it, add this to page-not-found.component.css:

p { text-align: center;
}

This is what the 404 page will look like.

Fix Routing Before Deployment

Since we’re using the Router service, all our routing is done on the client. If a link to a page in our app is pasted in the address bar (deep link) or there is a page refresh, that request we’ll be sent to our server. The server does not contain any of our routes because they were configured in the frontend, in our app. We’ll receive a 404 status in these instances.

To fix this, we need to tell the Netlify server to redirect all requests to our index.html page. This way our Angular router can handle them. If you’re interested, you can read more about this phenomenon here and here.

We’ll start by creating a _redirects file in our src folder. The _redirects file is a plain text file that specifies redirect and rewrite rules for the Netlify site. It should reside in the site publish site directory (dist/<app_name>). We’ll place it in the src folder and specify it as an asset in the angular.json file. When the app is compiled, it will be placed in dist/<app_name>.

touch src/_redirects

This file will contain the rule below. It indicates that all requests to the server should be redirected to index.html. We also add a HTTP status code option at the end to indicate that these redirects should return a 200 status. By default, a 301 status is returned.

/* /index.html 200

The last thing we have to do is add the below option in our angular.json und er projects > {your_project_name} > architect > options > assets. Include it in the assets array:

{ "glob": "_redirects", "input": "src", "output": "/"
}

Preview Your App Locally

Before you can deploy the feedback app, it’s best to preview it. This allows you to make sure your site works as you had intended it. You may unearth issues resulting from the build process like broken paths to resources among other things. First, you’ll have to build your app. We’ll then serve the compiled version using a server. We’ll use lite-server which is a lightweight live-reload server for web apps.

Note: Since the app is not deployed on Netlify just yet, you’ll get a 404 error when you attempt to make the post request. This is because Netlify Forms only work on deployed apps. You’ll see an error on the form as shown in the screenshot below, however, it will work once you’ve deployed it.

  1. To begin, install lite-server:
    npm install lite-server --save-dev
    
  2. Next, within your app’s workspace directory, build your app. To make sure builds are run every time your files change, pass the --watch flag to it. Once the app is compiled, the results are written to the dist/<app name> output directory. If you are using a version control system, make sure to not check in the dist folder because it is generated and is only for preview purposes.
    ng build --watch
    
  3. To serve the compiled site, run the lite-server against the build output directory.
    lite-server --baseDir="dist/<app name>"
    

The site is now served at localhost:3000. Check it out on your browser and make sure it works as expected before you begin its deployment.

Deployment

There are multiple ways you can deploy your Angular project onto Netlify Edge. We shall cover three here:

  1. Using netlify-builder,
  2. Using Git and the Netlify web UI,
  3. Using the Netlify CLI tool.

1. Using netlify-builder

netlify-builder facilitates the deployment of Angular apps through the Angular CLI. To use this method, your app needs to have been created using Angular CLI v8.3.0 or higher.

  1. From the Sites tab of your Netlify dashboard, create a new project. Since we won’t be using Git to create a project, drag any empty folder to the dotted-border area marked “Drag and drop your site folder here”. This will automatically create a project with a random name. You can change this name under the site’s domain settings later if you wish.


    This is what you should see once your project has been created.
  2. Before you can deploy using this method, you will need to get the Netlify project’s API ID and a Netlify personal access token from your account. You can get the project API ID from the site settings. Under Site Settings > General > Site Details > Site Information you will find your project’s API ID.


    You can get a personal access token in your user settings. At User Settings > Applications > Personal access tokens, click the New Access Token button. When prompted, enter the description of your token, then click the Generate Token button. Copy your token. For persistence’s sake, you can store these values in a .env file within your project but do not check this file in if you are using a version control system.
  3. Next, add netlify-builder to your project using ng add.
    ng add @netlify-builder/deploy
    

    Once it’s done installing, you will be prompted to add the API ID and personal access token.


    It’s optional to add these here. You could ignore this prompt because they will be added to your angular.json file which is usually checked in if you use a version control system. It’s not safe to store this kind of sensitive information on code repos. If you are not checking this file in, you could just input your API ID and personal access token. The entry below will be modified in your angular.json file under the architect settings.

    "deploy": { "builder": "@netlify-builder/deploy:deploy", "options": { "outputPath": "dist/<app name>", "netlifyToken": "", "siteId": "" }
    }
    
  4. All that’s left is to deploy your application by running:
    NETLIFY_TOKEN=<access token> NETLIFY_API_ID=<api id> ng deploy
    

    Alternatively, you could put this in a script and run it when you need to deploy your app.

    # To create the script
    touch deploy.sh && echo "NETLIFY_TOKEN=<access token> NETLIFY_API_ID=<api id> ng deploy" >> deploy.sh && chmod +x deploy.sh # To deploy
    ./deploy.sh
    

    This is the output you should see once you run this command:

2. Using Git And The Netlify Web UI

If your Angular app’s code is hosted on either Github, Bitbucket, or Gitlab, you can host the project using Netlify’s web UI.

  1. From the Sites tab on your Netlify dashboard, click the “New site from Git” button.
  2. Connect to a code repository service. Pick the service where your app code is hosted. You’ll be prompted to authorize Netlify to view your repositories. This will differ from service to service.
  3. Pick your code repository.
  4. Next, you’ll specify the deployments and build settings. In this case, select the branch you’d like to deploy from, specify the build command as ng deploy --prod and the publish directory as dist/<your app name>.
  5. Click the Deploy Site button and you’re done.

3. Using The Netlify CLI Tool

  1. To start, install the Netlify CLI tool as follows:
    npm install netlify-cli -g
    

    If the installation is successful, you should see these results on your terminal:

  2. Next, log in to Netlify by running:
    netlify login
    

    When you run this command, it will navigate to a browser window where you will be prompted to authorize the Netlify CLI. Click the Authorize button. You can then proceed to close the tab once authorization is granted.

  3. To create a new Netlify project, run the following on your terminal:
    netlify init
    

    You will be prompted to either connect your Angular app to an existing Netlify project or create a new one. Choose the Create & configure a new site option. Next, select your team and a name for the site you would like to deploy. Once the project has been created, the CLI tool will list site details for your project.
    After which the CLI tool will prompt you to connect your Netlify account to a Git hosting provider to configure webhooks and deploy keys. You cannot opt-out of this. Pick an option to login in then authorize Netlify.
    Next, you’ll be asked to enter a build command. Use:

    ng build --prod
    

    Afterward, you’ll be asked to provide a directory to deploy. Enter dist/<app name> with your app’s name.
    At the end of that, the command will complete and display this output.

  4. To deploy the app, run:
    netlify deploy --prod
    

    Using the --prod flag ensures that the build is deployed to production. If you omit this flag, the netlify deploy command will deploy your build to a unique draft URL that is used for testing and previewing. Once the deployment is complete, you should see this output:

Viewing Form Submissions

Form submissions can be viewed on the Netlify dashboard under the Forms tab of your site. You can find it at app.netlify.com/sites/<your_site_name>/forms. On this page, all your active forms will be listed. The name attribute that you put down in the hidden form element is the name of the form on the dashboard.

Once you select a form, all the submissions for that form will be listed. You can choose to download all the entries as a CSV file, mark them as spam, or delete them.

Conclusion

Netlify Forms allow you to collect form submission from your app without having to create or configure a backend to do it. This can be useful especially in apps that only need to collect a limited amount of data like contact information, customer feedback, event sign-ups, and so on.

Pairing Angular reactive forms with Netlify forms allow you to structure your data model. Angular reactive forms have the added benefit of having their data model and form elements being in sync with each other. They do not rely on UI rendering.

Although Netlify Forms only work when deployed on Netlify Edge, the hosting platform is pretty robust, provides useful features like A/B testing, and automates app builds and deployments.

You can continue reading more about using Netlify with your forms over here.

SEO: 5 Tips to Convert Visitors to Buyers

Search engine optimization focuses on driving consumers to your site. But traffic alone doesn’t pay the bills. Success depends on converting those visitors to customers.

Organic search traffic converts to revenue, on average, roughly 3 percent of the time, according to the studies I’ve seen, although the top converting sites reach 10 percent or more.

Remember that searchers drop onto your site with no navigational context. Searchers that query your brand typically have a goal in mind. Helping them accomplish that goal increases the likelihood of a purchase or at least a positive impression.

Others won’t know anything about your company. They haven’t seen the rest of your site — most of them won’t see your home page. They have no knowledge of the products you carry, the promotions you’re running, or what distinguishes your site.

Use these five tips to convert more searchers into buyers.

Converting Searchers into Buyers

1. Don’t rely on brand recognition. Most searchers chose your listing because it seemed at a glance to meet their needs.  It wasn’t because they recognized your company or the brands you carry.

For that reason, sites organized by product brand instead of type or feature will struggle in organic search. It’s harder for brand-oriented sites to rank for the non-branded queries that most people search for. It’s also harder for those non-brand searchers to navigate your site for the products and information they’re looking for.

2. Highlight promotions on every page. Prices are a major purchase consideration in most ecommerce sectors — the smaller your brand, the more important the price.

Unfortunately, most consumers coming from organic results will miss out on home page discounts or promotions. Spotlight those promotions on every page in some way.

Some sites use static or rotating banners across the top of all pages. Others display (i) a pop-up modal upon a visitor’s initial entry, (ii) a flag in the corner or on the side of the page, or (iii) a banner that slides up and down from the bottom of the page.

Test which of those work best for your audience and your site’s design.

3. Make them feel confident. There’s a good chance that any searcher you’re trying to convert has never been to your site. He might not have heard of your company.

Brands that are less prominent need more proof points than household names. Help searchers feel confident about purchasing from your site by displaying instant signs of trustworthiness, such as:

  • An about us page to give tangible substance to your business;
  • Trusted symbols and logos such as Google star ratings, Trustpilot, Better Business Bureau, and industry affiliations;
  • Your phone number. If your brand is a household name, placing the phone number in a less prominent position, such as your footer, is fine. If not, make it obvious as a sign that shoppers can contact your company quickly.
  • A chat feature for instant support.

4. Include product reviews. I’ve heard all of the objections to product reviews:

  • What if no one reviews anything?
  • What if there are negative reviews?
  • We don’t have time to moderate.

None of those outweigh the benefits. Reviews offer other shoppers an independent indicator of value. And for SEO, product reviews serve as an excellent source of unique, user-generated content, which enriches the product page‘s keyword theme overall.

If you don’t have product reviews, resist the temptation to add a raft of Google business reviews. They don’t help your SEO, and it reinforces the absence of reviewed products.

5. Help them choose. Most searchers, again, will have no experience with your brand. Thus they’re going to have a harder time choosing among your offerings. Incorrect choices lead to more returns and frustrated buyers.

Offer size guides, help icons, product comparison charts, and other features that inspire confidence and increase the likelihood that shoppers will choose the right product the first time.